Tengo una clase utilizada para procesar pagos de clientes. Todos menos uno de los métodos de esta clase son los mismos para todos los clientes, excepto uno que calcula (por ejemplo) cuánto debe el usuario del cliente. Esto puede variar mucho de un cliente a otro y no hay una manera fácil de capturar la lógica de los cálculos en algo así como un archivo de propiedades, ya que puede haber varios factores personalizados.
Podría escribir código feo que cambie según el ID de cliente:
switch(customerID) {
case 101:
.. do calculations for customer 101
case 102:
.. do calculations for customer 102
case 103:
.. do calculations for customer 103
etc
}
pero esto requiere reconstruir la clase cada vez que tenemos un nuevo cliente. ¿Cuál es la mejor manera?
[Editar] El artículo "duplicado" es completamente diferente. No estoy preguntando cómo evitar una declaración de cambio, estoy preguntando por el diseño moderno que mejor se aplica a este caso, que podría resolver con una declaración de cambio si quisiera escribir un código de dinosaurio. Los ejemplos proporcionados allí son genéricos y no son útiles, ya que esencialmente dicen "Hey, el interruptor funciona bastante bien en algunos casos, no en otros".
[Editar] Decidí ir con la respuesta mejor clasificada (crear una clase "Cliente" separada para cada cliente que implemente una interfaz estándar) por las siguientes razones:
Consistencia: puedo crear una interfaz que garantice que todas las clases de Clientes reciban y devuelvan el mismo resultado, incluso si fueron creadas por otro desarrollador
Mantenibilidad: todo el código está escrito en el mismo lenguaje (Java), por lo que no es necesario que nadie más aprenda un lenguaje de codificación separado para mantener lo que debería ser una característica simple.
Reutilización: en caso de que surja un problema similar en el código, puedo reutilizar la clase Cliente para mantener cualquier número de métodos para implementar la lógica "personalizada".
Familiaridad: ya sé cómo hacer esto, así que puedo hacerlo rápidamente y pasar a otros problemas más urgentes.
Inconvenientes:
Cada nuevo cliente requiere una compilación de la nueva clase de Cliente, lo que puede agregar cierta complejidad a la forma en que compilamos e implementamos cambios.
Un desarrollador debe agregar a cada nuevo cliente; una persona de soporte no puede simplemente agregar la lógica a algo así como un archivo de propiedades. Esto no es ideal ... pero tampoco estaba seguro de cómo una persona de Soporte podría escribir la lógica de negocios necesaria, especialmente si es compleja con muchas excepciones (como es probable).
No escalará bien si agregamos muchos, muchos clientes nuevos. Esto no se espera, pero si sucede, tendremos que repensar muchas otras partes del código además de esta.
Para aquellos de ustedes interesados, pueden usar Java Reflection para llamar a una clase por su nombre:
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);