One of the pillars of object-oriented programming is the inheritance or the ability to create hierarchies of objects where you are refining or modifying certain behavior. For the sake of an example, imagine a company that sells washing machines, stoves and blenders. To motivate their vendors, they have a bonus system that works in the following way:
All vendors have a sales quota. If 25% of sales are coming from washing machines, the seller gets a bonus of 15% of their salary. If at least 50% of the sales come from selling blenders, then receives a bonus of 30% of their salary. Finally if it achieves 25% of its share selling stoves gets a bonus of 20% of their salary.
Now, suppose that these vendors are distributed in the areas north, East and South. Vendors in the southern area have an additional 10% bonus if they exceed the sales quota.
We could represent it in the following way:
Then we have a class BonusCalculator. Objects of this class contain all the rules to calculate the bonus of any vendor. One way of implementing this might be something like:
public interface Vendor { bool SalesPercentAchieved(double percent, string productLine); } public class BonusCalculator { public virtual decimal CalcBonus(Vendor vendor) { decimal bonus = 0; bonus = washMachineSellingBonus(vendor); bonus += blnderSellingBonus(vendor); bonus += stoveSellingBonus(vendor); return bonus; } ... }
However for vendors in the South, we have an additional rule to all others.
public class SouthernBonusCalculator:BonusCalculator { override CalcBonus(Vendor vendor) { decimal bonus = base.CalcBonus(vendor); bonus + = overSellingBonus(vendor); return bonus; } ... }
That’s it. Just use the correct object to calculate the bonus.
void main() { List<Vendor> vendors = getVendors("North"); vendors.AddRange(getVendors("Eastern")); var calculator = new BonusCalculator(); for each(var vendor in vendors) { decimal bonus= calculator.CalcBonus(vendor); Console.WriteLine (bonus); } calculator = new SouthernBonusCalculator(); List<Vendor>SouthernVendors= getVendors("South"); for each(var vendor in SouthernVendors) { decimal bonus= calculator.CalcBonus(vendor); Console.WriteLine (bonus); } }
Simple. This code leaves much to be desired but we will go adjusting it later.
Now I would like to point out that there’s no properties in the diagram nor in the code.
I did this deliberately to place emphasis on a fundamental principle: inherits it’s all about the behavior, not the data. In other words we use inheritance when we have an object that has a method that you want to adjust a bit to your needs, not when we want to reuse data. That is a common mistake. It comes from the relational databases mindset, which is reduce the duplication of data. In the case of object-oriented programming, it is reducing duplication of methods. Don’t be afraid to repeat data on different objects.
Well that is all for today, next time we will see the meaning of the phrase “favor composition over inheritance” and how that can help us improve the code for this example. Until then.