< Day Day Up > |
Let's say you have reserved a rental car for a trip to San Francisco. You have a confirmation for a car. A midsize car has been requested , but the exact make of the car won't be known until you get to the car rental counter and see what is actually available. But that doesn't preclude you from reserving the car. The actual make of the car will be known at runtime. This is polymorphism. In other words, polymorphism is the ability for objects to act like other objects in the inheritance hierarchy. What Is It Again?Polymorphism is an object-oriented mechanism that enables the method version executed to be determined at runtime based on the datatype of the object instance. It lets us use a superclass object datatype, knowing that at runtime, the object datatype will be of a subclass object datatype. We do this because the object datatype can be determined only at runtime. In our loan calculator application, we use polymorphism. In Listing 5.14, you can see that depending on the user 's selection at runtime, the type of loan could be car or mortgage. The loan instance variable has a static datatype of type Loan . However, at runtime, the loan instance could hold either a Mortgage instance or a CarLoan instance (called dynamic or actual datatype). In either case, the call to getMonthlyPayment( ) is identical. Listing 5.14. Object Datatypingvar loan:Loan; static datatype if (loanType.selectedData == "m"){ loan = new Mortgage(...)); datatype determined at run-time }else{ loan = new CarLoan(...); datatype determined at run-time } //calculate the monthly payment var monthlyPmtVal:Number = loan.getMonthlyPayment(); How Does It Work?To better understand polymorphism, we can look at object datatyping and the superclass-subclass relationship. In the process, we will discover how casting, which is the changing of an object from one type to another, plays a key role in polymorphism. Starting with object datatypes, Figure 5.7 shows a legal assignment with regard to the Loan class hierarchy. Notice that a variable of a superclass datatype can be used to reference an instance of a subclass. Figure 5.7. Legal object assignment.
When we create a variable of a particular type, the blueprint for that type is loaded and used to validate its usage. Because any subclass has everything its superclass has, there is no problem when a superclass blueprint is used to validate a subclass. Although there will be many times when you will want to use the superclass datatype to point to a subclass instance, there is one limitation: Only the methods defined in the superclass can be invoked. In Figure 5.7, when we tried to execute a mortgage method, calculatePropertyTax() , the compiler generated an error. The method we want to execute would be that of the actual (dynamic) type of the object and not the method of the reference variable (static) type.
Because a subclass can have new members that are not in the superclass, the compiler will complain when we use a subclass reference variable to point to a superclass, as shown in Figure 5.8. Figure 5.8. Illegal type assignment.
CastingAnother important concept for polymorphism is casting . ActionScript 2.0 lets you cast one datatype to another. The cast operator that Flash uses takes the form of a function. When you cast a variable from one type to another, you are telling the compiler that the actual type of the object will be different at runtime. The compiler treats the object as having a set of properties that its initial datatype does not contain. This can be useful, for example, when iterating over an array of objects that might be of differing types.
The syntax for casting is a function syntax, as seen in Figure 5.9. The function call is newtype(instance) where you want the compiler to behave as if the datatype of instance is newtype . Casting is used when the compatibility can be determined only at runtime. Figure 5.9. Casting example.
In Listing 5.15, we have used polymorphism to calculate and display the loan payments. Notice that this function takes an argument of type Loan . Listing 5.15. Polymorphism in the calc Methodfunction calc(loanInstance:Loan){ //function called by the button handler //calculate and display the monthly payment //the actual run-time datatype could be CarLoan or Mortgage //regardless, getMonthlyPayment() will return the correct results var monthlyPmtVal:Number = loanInstance.getMonthlyPayment(); monthlyPmt.text = monthlyPmtVal; //calculate and display total payments var totalPmtVal:Number = loanInstance.getTotalPayment(); totalPmt.text = totalPmtVal; } Because we know that the Loan class defines the calculate methods, we can call the methods regardless of the actual datatypes of the class passed in. We know that the actual type of the argument can be either Mortgage or CarLoan , as shown in Listing 5.16. Listing 5.16. Passing loan to the calc Methodthis.calc_btn.onPress = function(){ var loanInstance:Loan; if (loanType.selectedData == "m"){ loanInstance = new Mortgage(loanAmt, term, rate); }else{ loanInstance = new CarLoan(loanAmt, term, rate); } this._parent.calc(loanInstance); } Another example of polymorphism can be seen in Listing 5.17. The Employee and Manager classes both have methods for calculating bonuses. In an application used for handling bonus letters , each object, Employee and Manager , uses different algorithms to calculate bonuses. In Listing 5.17, the object of type Employee is passed and letters are printed. The runtime datatype of the object can be either Employee or Manager . Listing 5.17. Polymorphism ExampleprocessBonusLetter(emp:Employee){ var empName = emp.getName(); var empBonus = emp.getBonus(); bonus calculate based on emp type print(empName, empBonus); } For programmers new to OOP, polymorphism can be a challenging concept to grasp. As you gain experience in OOP, polymorphism becomes clearer. In most cases, polymorphism opportunities have a way of exposing themselves rather than being planned into an application. |
< Day Day Up > |