Friday, October 12, 2007

Object Oriented Programming

View this post on my website
http://blog.go4flash.com/articles/as3/as3-oop/

ActionScript 3.0 is called object-oriented because it supports inheritance, encapsulation and polymorphism.

The first two notions can be easily defined.

Inheritance allows you to design a class by deriving it from an existing one. This feature allows you to reuse existing code without doing copy and paste.
For example:
//ancestor
package com.ryaco.ui{
public class ControlExt {
var name:String;
}
}
// descendant
package com.ryaco.ui{
public class Slider extends ControlExt {
var name:String;
}
}
// descendant
package com.ryaco.ui{
public class Grid extends ControlExt {
var name:String;
}
}

Encapsulation is an ability to hide and protect data. In other words encapsulation is what makes a code object an object. Encapsulation has been used synonymously with other terms such as component and module.

In the context of OOP, encapsulation is often called a black box, meaning you can see it do certain things but you cannot see the inner workings.

AS3 has access level qualifiers such as public, private, protected and internal to control the access class variables and methods.
For example:
package com.ryaco.ui{
public class Preloader extends MovieClip {
private var _progress:Number;
//constructor
public function Preloader(){
_progress = 0;
}
//public methods
public function setProgress(prgs:Number):void{
_progress = prgs;
// do some other actions e.g. change progress bar width, displaying progress value in text field etc.
}
}
}

In this case we don't need to know about _progress variable, just need to know how to work with setProgress method (i.e. which parameters we have send there).

Now we can speak about
Program Design with Interfaces and Polymorphism.
To illustrate how you can design AS3 programs with interfaces, let’s work on the following assignment:
We have 2 components: Grid and List. Design classes to represent this components. The classes may have the following methods: doSelect, getSelected and setData.

First we will add all common methods that are applicable to all components to the class ComponentExt
package com.ryaco.ui{
public function setData(data:Array):String{
return "New data: "+data.join(",");
}
}
In the next step, we will add a new behavior that can be reused by multiply classes: an ability to select and get selected row or tab. Let's define an interface Selectable:
package com.ryaco.ui{
public interface Selectable{
function doSelect(index:Number):String;
function getSelected():String;
}
}

More then one class can implement this interface
package com.ryaco.ui{
public class Grid extends ComponentsExt implements Selectable{
public function doSelect(_index:Number):String{
//Grid-specific code goes here...
return "Class Grid: Select row number "+_index;
}
public function getSelected():String{
//Grid-specific code goes here...
return "Class Grid: return Selected row";
}
}
}

package com.ryaco.ui{
public class List extends ComponentsExt implements Selectable{
public function doSelect(_index:Number):String{
//List-specific code goes here...
return "Class List: Select row number "+_index;
}
public function getSelected():String{
//List-specific code goes here...
return "Class List: return Selected row";
}
}
}

When the class Grid declares that it implements interface Selectable, it “promises” to provide implementation for all methods declared in this interface - in our case it is two methods doSelect and getSelected. Why is it so important that the class will “keep the promise” and implement all interface’s methods? An interface is a description of some behavior(s). In our case the behavior Selectable means existence of a methods with the signature
doSelect(_index:Number)
getSelected()
If any other class knows that Grid implements Selectable, it can safely call any method declared in the Selectable interface

A class can’t have two independent ancestors, but it can implement multiple interfaces, it just needs to implement all methods declared in all interfaces.
e.g. class Grid extends ControlExt implements Selectable, Editable {…}
If you interested only in Selectable functions, you can cast the object only to those interfaces which you intend to use, for example:
var seGrid:Grid = new Grid();
var sGrid:Grid = seGrid as Selectable;

Now we will write class ComInit, which will use defined classes Grid and List. It'll create an array with a mix of Grids and Lists. Iterate through this array and cast it to Selectable interface, and then call the method doSelect() on each object in this collection

package com.ryaco.ui{
public class ComInit {
public function ComInit (){
var components:Array = new Array();
components.push(new Grid());
components.push(new List());
components.push(new List());
components.push(new Grid());
for(var i: int = 0; i < selectable=" components[i]" style="font-weight: bold;">Polymorphism – when you look at our ComInit, it looks like it calls the same method doSelect() on different types of objects, and it generates different output for each type. This is an example of polymorphic behavior. It allows you to avoid using switch or if statements with the type checking operator is. You don't need to modify the code each time you add a new selectable component type.


info for java developers: Comparing the syntax of Java 5 and ActionScript 3.0

links: AS3 vs Java, OOP