This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
The employees of a company are divided into various types based on the allowances they get.
i) Employees who just get their salary. ii) Employees who get salary plus a 20% of their salary as bonus iii) Employees who get salary plus a 20% of their salary as bonus plus 10% of their salary as a super bonus.
The payroll application should calculate the pay for these employees based on the above mentioned rules. (it is essential that the payroll application should be able to get the salary and bonus parts separately)
I'd be more inclined to create a Pay, BonusPay, and SuperBonusPay set of classes, and assign an instance to the employee to each one. That way at the abstract level you've got "Every Employee gets a Pay." At the concrete level you've got logic assigning each specific Employee type to a specific Pay type.
Make visible what, without you, might perhaps never have been seen. - Robert Bresson
Robert Martin's Agile Software Development has a pretty complete payroll system as a case study. I don't have it at hand, but I think each employee has a strategy or two for computing salary, deductions, union dues, etc.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Although this is a classic case of business rules, and for a real-world solution, a rule-based system such as Jess would be worth thinking about.
Absolutely. An interesting exercise example, if nothing else.
Joined: Dec 24, 2004
Thanks for all the replies. Let me take a different example.
The service charge for shipping a product is 5% of the cost of the product. The service charge is exemted (0%) for some products (say goods shipped to Red Cross). An additional 2% of service charge is applicable to all products which has to be sent via express service.
So, we have the following possibilities
Normal product & ordinary service: 5% Red cross product & ordinary service: 0% Normal product & express service: 7% Red cross product & express service: 2%
The idea is to calculate how much each product costs (cost + service charge) and what is the total service charge applicable to a cargo pack (which can have multiple products).
Based on your suggestions, I have come up with the following design. Let me know your inputs.
I will go ahead and assign a suitable instance of ServiceCharge type to each product depending upon the business rules (Does Factory Method pattern fits here?). Now I have some questions
i) Whether the getServiceCharge() method should return just the percentage or should it calculate the service charge and return the actual amount (for this I need to pass the cost of the product to this method).
ii) How do I handle the ExpressServiceCharge? As said earlier, ExpressServiceCharge is an additional Service charge applicable to all products sent in a express service. I'm not able to find a way to represent this relationship properly.
I think this is an even better case for the Decorator pattern for a couple reasons:
The modifiers (customer is/isn't Red Cross, carrier) are independent.
If more categories of modifiers were added, it would cause an explosion of classes.
Sure, now you have only four different ServiceCharge subclasses. But what if you then have to modify the service charge for whether you ship weekend versus weekday and whether the destination is in-state versus out-of-state? You'd then have 4*2*2 = 16 subclasses.
It makes sense to have Product have a ServiceCharge field, so let's keep those two classes pretty much as-are.
I'd then define a concrete DefaultServiceCharge class that returns the basic 5% for getServiceCharge().
Next comes the ServiceChargeDecorator intermediate class that defines the Decorator things, such as a constructor that takes a ServiceCharge arg and the instance field to assign that arg to. And finally I'd define the various subclasses of ServiceChargeDecorator. If we say that the default service charge returned by a basic DefaultServiceCharge object is 5%, then the RedCrossServiceChargeDecorator.getServiceCharge() could return clientServiceCharge.getServiceCharge()-5%, and ExpressServiceChargeDecorator.getServiceCharge could return clientServiceCharge.getServiceCharge()+2%.
What I don't like with that setup is that the value of the default service charge (5%) is duplicated in both the DefaultServiceCharge class AND the RedCrossServiceChargeDecorator. (I'm sure that if the basic service charge ever went up to 6%, the Red Cross would take off 6%.) That value should be defined just once and all classes that need that value should access it from the one spot. I suppose making the default service charge a final static in DefaultServiceCharge is as good a place to keep it as any. That would mean that the basic DefaultServiceCharge.getServiceCharge() would return defaultServiceCharge and RedCrossServiceChargeDecorator.getServiceCharge() would return clientServiceCharge.getServiceCharge()-ServiceCharge.defaultServiceCharge.
But then one subclass needs to know about another. Maybe the default service charge can be defined in the ServiceCharge interface? Ick. Maybe another whole class should be made to hold that constant. I, personally, would be a little quick and dirty and put that value in the DefaultServiceCharge class.
I can see it now...
[ September 08, 2005: Message edited by: Ryan McGuire ]