I have a class used to process customer payments. All but one of the methods of this class are the same for every customer, except for one that calculates (for example) how much the customer's user owes. This can vary greatly from customer to customer and there is no easy way to capture the logic of the calculations in something like a properties file, as there can be any number of custom factors.
I could write ugly code that switches based on customerID:
switch(customerID) {
case 101:
.. do calculations for customer 101
case 102:
.. do calculations for customer 102
case 103:
.. do calculations for customer 103
etc
}
but this requires rebuilding the class every time we get a new customer. What is the better way?
[Edit] The "duplicate" article is completely different. I'm not asking how to avoid a switch statement, I'm asking for the modern design that best applies to this case -- which I could solve with a switch statement if I wanted to write dinosaur code. The examples provided there are generic, and not helpful, since they essentially say "Hey, the switch works pretty good in some cases, not in some others."
[Edit] I decided to go with the top-ranked answer (create a separate "Customer" class for each customer that implements a standard interface) for the following reasons:
Consistency: I can create an interface that ensures all Customer classes receive and return the same output, even if created by another developer
Maintainability: All code is written in the same language (Java) so there is no need for anyone else to learn a separate coding language in order to maintain what should be a dead-simple feature.
Reuse: In case a similar problem crops up in the code, I can reuse the Customer class to hold any number of methods to implement "custom" logic.
Familiarity: I already know how to do this, so I can get it done quickly and move on to other, more pressing issues.
Drawbacks:
Each new customer requires a compile of the new Customer class, which may add some complexity to how we compile and deploy changes.
Each new customer has to be added by a developer -- a support person can't just add the logic to something like a properties file. This is not ideal ... but then I also wasn't sure how a Support person would be able to write out the necessary business logic, especially if it is complex with many exceptions (as is likely).
It won't scale well if we add many, many new customers. This is not expected, but if it does happen we'll have to rethink many other parts of the code as well as this one.
For those of you interested, you can use Java Reflection to call a class by name:
Payment payment = getPaymentFromSomewhere();
try {
String nameOfCustomClass = propertiesFile.get("customClassName");
Class<?> cpp = Class.forName(nameOfCustomClass);
CustomPaymentProcess pp = (CustomPaymentProcess) cpp.newInstance();
payment = pp.processPayment(payment);
} catch (Exception e) {
//handle the various exceptions
}
doSomethingElseWithThePayment(payment);