Tengo una clase utilizada para procesar los pagos de los 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 cualquier número de factores personalizados.
Podría escribir un código feo que cambia 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 obtengamos 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 aplique 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 de "Cliente" por cada cliente que implemente una interfaz estándar) por las siguientes razones:
-
Coherencia: puedo crear una interfaz que garantice que todas las clases del Cliente reciban y devuelvan el mismo resultado, incluso si es creado por otro desarrollador
-
Mantenimiento: 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 función sencilla.
-
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 hacerlo, así que puedo hacerlo rápidamente y pasar a otros temas más urgentes.
Inconvenientes:
-
Cada nuevo cliente requiere una compilación de la nueva clase de clientes, lo que puede agregar cierta complejidad a la forma en que compilamos e implementamos los cambios.
-
Cada nuevo cliente debe ser agregado por un desarrollador: una persona de soporte no puede simplemente agregar la lógica a algo 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 se escalará bien si agregamos muchos, muchos nuevos clientes. Esto no se espera, pero si sucede, tendremos que repensar muchas otras partes del código, así como esta.
Para aquellos de ustedes interesados, puede 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);