AS1 OOP: Prototypes
         by senocular  

Getter and Setter Properties
Often you may find yourself writing methods whose sole purpose is to alter a particular single property or aspect of an instance. An existing example of this can be seen in the MX scrollbar component with setEnabled. You can set the enabled aspect of the scrollbar by passing in either true or false to that setEnabled method. There's also a method to check that value, getEnabled. Now if you think about regular buttons, they too have an enabled aspect. For regular buttons, though, enabled is a property handled by direct assignment and not through methods such as setEnabled and getEnabled for a scrollbar. If they are doing the same thing, one would think the scrollbar too could have just a property instead of using methods, right? Well, the problem is that a scrollbar is made up of many buttons and elements that require extra effort to actually "disable" the scrollbar, therefore it must use a method to handle all the necessary operations needed to turn the scrollbar from enabled to disabled. Though it may seem like a minor infection of enabled standards, there is a cure. That cure lies in addProperty.

The addProperty method is a function allowing you to create a property in an object (which could be a prototype object) that uses two functions, a get and set, to handle its definition. The get function is used when the property is checked and the set function when it's assigned a value. This allows the conversion of two functions into one property.

scrollbar.setEnabled(true);
trace(scrollbar.getEnabled()); // traces true

to

scrollbar.enabled = true;
trace(scrollbar.enabled); // traces true

Get and set methods are accessor methods. They provide a method interface to a property or aspect of an object. Using addProperty, you have the ability to make a property that behaves based on defined accessor methods. This allows your basic property to behave in a very strict manner. For instance, you could set up a property that, though it may have been assigned one value, returns another – all based on the definition of the get and set functions. A more practical use would be to assure that the values assigned to the "property" are valid ones. As an example, lets say we wanted a selected track for a certain album object. This album object would only have a certain number of songs, so we need to make sure a requested track is valid within that listing.

Album = function(title, artist, tracksArray){
this.title = title;
this.artist = artist;
this.tracksArray = tracksArray;
this.$selected = 1; // used to hold the "real" selected track number
};
getSelected = function(){
return this.$selected;
};
setSelected = function(trackNum){
if (trackNum < 1){
trackNum = 1;
}else if (trackNum > this.tracksArray.length){
trackNum = this.tracksArray.length;
}
this.$selected = trackNum;
};
Album.prototype.addProperty("selected", getSelected, setSelected);
nowPlaying = new Album("OOP - Yeah You Know Me", "The Flashers", ["A", "B", "C"]);
nowPlaying.selected = 2;
trace(nowPlaying.selected); // traces 2
nowPlaying.selected = 20;
trace(nowPlaying.selected); // traces 3

You can see here that the added getter/setter property was added to the prototype of the Album class. That will still work fine for any instance of Album – just as it were any other method or property defined there. It will be accessible to all instances just the same. Notice too that the getSelected and setSelected are not methods defined in the Album prototype. This is because addProperty does not use current methods of an object, but rather, as its name suggests, adds them – actually copying them. So whatever methods are used in the addProperty call will be added to the object though only accessible through the use of that property. If you want, you can delete the original functions if you don't want them lingering around. You could use also prototype methods if you wanted to, though they will be added into the object a second time – once as they exists as prototypes, and again for use in the new property. This of course may be desired if you want both method and property access to the aspect. In defining those, just be sure to reference the function fully.

Album.prototype.addProperty("property", Album.prototype.getSelected, Album.prototype.setSelected);

Also, if you noticed, in the Album example there was a need to keep a "real" hidden property to represent the actual selected property. The selected property as it was defined by addProperty was just a method for changing the real thing. Here, a $ was used to separate the getter/setter property from the real one. The difference in variable names didn't have to be a $. It could have been another variable all together – just something to keep hold the desired end value. The use of $ serves as an easily seen indicator that the property is considered "hidden" as you don't often see variables using the dollar sign in Flash. Feel free to use what you are most comfortable with when dealing with these kinds of situations.

For one more example, we can make something similar to that of the enabled scrollbar. This, instead, will be a .collapsed property for a simple menu. When not collapsed, the menu is its normal size and visible. When collapsed, it's compacted into just an icon.

Example:

[ hidden property set to true when mouse is down ]

// the menucontrol class controls a menu movieclip
// in the main timeline.
MenuControl = function(menu, icon_name){
this.menu = menu;
this.icon_name = icon_name;
};
getCollapsed = function(){
// if any non-icon clip has
// a false _visible property then
// collapsed is true (!false = true)
for (var item in this.menu){
if (item != this.icon_name){
return !this.menu[item]._visible;
}
}
};
setCollapsed = function(visible){
// cycle through all clips in the menu
// clip. If it has a _visible property
// set its value to be the value set by
// the assignment of .collapsed
for (var item in this.menu){
if (item != this.icon_name){
if (this.menu[item]._visible != undefined){
this.menu[item]._visible = !visible;
}
}
}
};
// create the property
MenuControl.prototype.addProperty("collapsed", getCollapsed, setCollapsed);
// delete the functions used as there is no longer a need for them
delete getCollapsed;
delete setCollapsed;

 
// menu is a movieclip on the main timeline
// icon is one of many movieclips inside menu
// when collapsed, all other movieclips (not icon)
// are set to be invisible. When collapsed is false
// then all movieclips are set to be visible
menu = new MenuControl(menu_mc, "icon");

 
// add some basic interactivity using buttons
// to deomonstrate collapsing of the menu
false_btn.onRelease = function(){
menu.collapsed = false;
trace("hidden: "+ menu.collapsed);
};
true_btn.onRelease = function(){
menu.collapsed = true;
trace("hidden: "+ menu.collapsed);
};

 

download source

 

Prev Page
 



SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.