If you ask a developer what Polymorphism means, they'll become an expert in Ancient Greek and declare it means "having many forms".
Polymorphism is achieved through polymorphic references, which are variables that are capable of referring to multiple object types.
Monomorphic References
When we first learned about variables and objects, we learned about the different types.
String firstname = 'Saman'; Boolean isCoolGuy = true;
These are monomorphic references. We can only assign strings to the variable firstName
, and we can only assign a boolean to isCoolGuy
. Trying to assign anything else would cause compilation errors. Polymorphic references work differently.
Binding and Polymorphic References
IProduct productA; // ... // code that assigns productA productA.calculateTotalPrice();
productA
is a polymorphic reference that has the ability to reference various object types at different times. However, it is not capable of referencing just any object; instead, it can only reference objects that are derived from it, specifically any class that implements the IProduct
interface.
Assuming HardwareProduct
, SoftwareProduct
, and ProfessionalServicesProduct
all implemented IProduct
, you could build a list, and dynamically call the calcualteTotalPrice
method on each one:
List<IProduct> productList = new List<IProduct>(); productList.add(new HardwareProduct('Servers')); productList.add(new SoftwareProduct('Licenses')); productList.add(new ProfessionalServicesProduct('Consultant')); Decimal sum = 0; for(IProduct p : productList){ sum += p.calculateTotalPrice(); }
Linking a method call to its corresponding method implementation is called binding. Most of the time, binding in Apex happens at compile time. For polymorphic reference, the object reference is not known until the line of code is executed, so binding has to wait until runtime. This is called late binding or dynamic binding. Dynamic binding is possible because of the contract established between the concrete class and the interface.
IAccount Polymorphic Reference
In our ongoing example, you created a hierarchy by creating a subclass, BusinessAccount
, that implements the IAccount
interface. Now, we can create our polymorphic reference to achieve polymorphism.
These two code blocks both compile and have the same result:
BusinessAccount bAccount = new BusinessAccount(); // a monomorphic reference bAccount.placeOrder(customerOrder); PersonAccount pAccount = new PersonAccount(); // another monomorphic reference pAccount.placeOrder(customerOrder2);
IAccount anyAccount = new BusinessAccount(); // Polymorphic reference established anyAccount.placeOrder(customerOrder); // Calls the appropriate implementation from BusinessAccount anyAccount = new PersonAccount(); anyAccount.placeOrder(customerOrder2); // Calls the appropriate implementation from PersonAccount
The second code block shows we can use the IAccount
type to reference both PersonAccount
objects and BusinessAccount
objects. This comes in handy with method parameters and arguments. Let's take advantage of this in the OrderController
.