Sep

14

As Object-Oriented Programmers, our ultimate goal is reuseability. As our applications begin to grow, however, we discover that simply writing object classes and extending them does not provide the flexibility that we need. In fact, with an extremely complex application, this type of architecture does not simply create organizational headaches, it can also degrade performance. In the end, you are left with a messy plate of spaghetti code. So how can you get that flexibility in a complex application? Enter composition and polymorphism.

Merriam-Webster defines Polymorphism as the quality or state of existing in or assuming different forms. In terms of programming, it is a way of creating object classes that can exist as several different data types. A simple way of doing this is through inheritance, however after you go so many levels deep, you begin to lose who came from where. This is the point when code begins to get unwieldy. Through composition, or, as Merriam-Webster once again states, a product of mixing or combining various elements, we can achieve the same polymorphic outcome in a much more organized way. To achieve this in Actionscript, we utilize a combination of class objects and Interfaces.

An Actionscript interface is a special form of a class that simply defines a collection of publicly exposed methods. Unlike a class file, though, an interface is never actually instantiated as an object, it never defines the function of the methods it contains, and it can only has PUBLIC functions. Upon initial consideration, an interface seems relatively useless, but used within a composition design it becomes a very powerful tool because it frees us from the binds of multiple inheritance to derive our polymorphic classes. To demonstrate this, let us consider the following interfaces: Transportation, Vehicle, Boat, MotorizedMachine, and NonMotorizedMachine. From these interfaces we compose the following classes: SportsCar, Bicycle, Kayak, and Yacht. Lastly, we create a Person class, a Garage class, and a Dock class.

Our interfaces would have methods that are specific for their defined types, so methods for a Vehicle interface might be different than methods for a Boat interface. This is what creates the uniqueness of each interface. In composing our object classes now, we pick the interface(s) that best describe what our object is. In the case of a SportsCar, we would want to implement Transportation, Vehicle and MotorizedMachine. It would look like this:


class SportsCar implements Transportation, Vehicle, MotorizedMachine {

    //Specific code defining SportsCar goes here...

}

For a class that implements an interface, every method in the interface(s) must be defined in the class. For example, if Vehicle has a method for “moveForward”, SportsCar now has to define the exact execution of “moveForward”. So while an interface describes all of the methods which make up its data type, a class that “implements” that interface defines how those methods actually work. This means that for every class that implements, say, MotorizedMachine - SportsCar and Yacht - we now have a standardized method to call. MotorizedMachine might define a startEngine method, and while both SportsCar and Yacht need to implement this method, they do not need to be functionally the same.

With the newly composed classes, polymorphism starts to become evident when we describe the interaction with these composed objects. Earlier we defined that we would have a Person class, Garage class and a Dock class. These classes describe our interaction with our SportsCar, Bicycle, Kayak and Yacht. For the Person class, we want this object to interact with all of the objects that we make. To define each one individually would be a bit of a pain, but since they all implement Transportation, we can say that a Person object can interact with any Transportation object. Likewise, if we want the Person object to be able to startEngine of our SportsCar and our Yacht, it would not make any sense to say SportsCar.startEngine() and Yacht.startEngine(). What would happen if we added a third type of object, like a CommuterPlane or CompactCar? We would need to change our Person object to represent this change. However, since each of these implements MotorizedMachine, our Person object can simply interact with the MotorizedMachine. Any time we add a new object that implements MotorizedMachine, our Person object can now automatically call startEngine of that object.

This interaction is echoed in our Garage and Dock classes. We want to only store Vehicle objects in the Garage, and make sure that Boat objects are stored in the Dock. Looking now at our Yacht class, we can see how much more flexible it is through its composition. A Person can interact with it because it is of Transportation type, and can start the engine because it is of type MotorizedMachine. Additionally, we can store our Yacht in a Dock object because it is also of type Boat. And because we can use these different types for the same object, neither the Person object nor the Dock object ever needs to know that the actual type is Yacht.

This ability to define certain sets of functionality within an Interface, and then to implement those sets that best describe our objects is the core essence behind composing a polymorphic object class. In this way you can build a robust application that has the scalability and flexibility to grow, while still maintaining a critical level of control over your architecture.


Blogroll