El mejor patrón de diseño de OOP para una secuencia de operaciones

11

Estoy trabajando en una aplicación, cuyo módulo realiza las siguientes operaciones financieras secuencialmente:

Cuando un usuario solicita que se transfiera una cierta cantidad a su cuenta bancaria:

  1. verificar si alguna transacción puede suceder ahora? (la transacción puede llevarse a cabo solo durante un cierto período de tiempo)
  2. verificar si el usuario ha solicitado que se retire un monto mínimo
  3. verificar si el usuario tiene una cuenta predeterminada

El resultado de todas las acciones anteriores debe registrarse.

Si toda la condición anterior satisface, la transacción se lleva a cabo. En el futuro, podría haber algunas verificaciones adicionales.

¿Qué patrón de diseño orientado a objetos debería ser el más adecuado para el caso anterior?

kumar
fuente
3
Nunca busque un patrón de diseño para resolver un problema. Use patrones de diseño para comunicar la solución correcta. programmers.stackexchange.com/questions/70877/… Siga los principios de SOLID y no se equivocará.
pdr
2
Estoy en desacuerdo. Los patrones tienen nombres que facilitan la comunicación y también deben usarse para comunicar soluciones. Pero no estoy de acuerdo con "Nunca busque un patrón de diseño para resolver un problema". No solo resuelven problemas específicos, sino que también se enfrentan a diferentes fuerzas y limitaciones. Echa un vistazo a "Proxy" y "Decorador". Se ven similares pero resuelven diferentes problemas. Entonces, en mi opinión, antes de resolver un problema usted mismo, al menos debería echar un vistazo a los patrones de diseño conocidos para beneficiarse de ambos, un enfoque estándar para resolver un problema y una forma fácil de comunicarlo.
Jonny Dee
10
Aquí hay una buena caracterización de lo que es un patrón: "Ellos [los patrones] proporcionan soluciones de trabajo, concretas y adaptables a problemas que surgen repetidamente en ciertas situaciones durante el desarrollo de software, desde contextos organizacionales hasta contextos de programación". [POSA5, pág. 30] Entonces, desde este punto de vista, es totalmente claro que buscar un patrón como una solución adaptable es un enfoque legítimo.
Jonny Dee
3
¿Está solicitando una construcción orientada a objetos para describir la programación procesal antigua y simple?
mouviciel
44
Sigue el principio de KISS. Hasta ahora, su problema se puede resolver con 3 declaraciones "if" en un solo método. No intentes usar un patrón de diseño solo por el hecho de ser genial. Cada vez que escriba una clase adicional, siempre piense: ¿Realmente necesito eso?
Eiver

Respuestas:

13

Parece que lo que estás buscando es una Cadena de Responsabilidad . En este caso, podría tener las siguientes clases:

  • TransactionValidatorBase clase base abstracta
  • TransactionTimeValidator
  • TransactionAmountValidator
  • TransactionAccountValidator

Se encadenan para aplicar las reglas que especifique.

Lectura adicional

pswg
fuente
11
Tengo entendido que la Cadena de responsabilidad es más un filtro, es decir, vamos por la cadena hasta encontrar a alguien equipado para hacer frente a la responsabilidad, entonces ese "eslabón" se encargará de la responsabilidad y saldrá. Una falla en COR en términos prácticos es que es difícil hacer que devuelva un valor, que parece que podría necesitar para esto.
Amy Blankenship
Creo que puedes tener una Cadena de R. de un nivel. Realmente no creo que sea difícil devolver un valor de una Cadena, con un poco de distracción. Se requerirá que cada nivel se comunique adhiriéndose a una determinada interfaz primitiva, y se requerirá que acepte la entrada desde abajo, dado que dicha entrada se ajusta a la interfaz primitiva. Cuando se necesita la riqueza de la interfaz entre dos niveles de la Cadena que están más íntimamente acoplados, la abstracción puede transformarse en Poly para dar soporte a eso.
Andyz Smith
2

El patrón correcto aquí realmente depende de un contexto. Antes de elegir cualquier patrón en particular para seguir, trataré de encontrar respuestas a esas preguntas:

  • ¿Es necesario crear diferentes combinaciones de verificaciones (1,2,3) en tiempo de ejecución?
  • ¿Necesitan las mismas variables para realizar sus acciones o son muy diferentes?
  • ¿Qué tan precisos deberían ser los mensajes de error?
  • En caso de falla, ¿el usuario vuelve a intentarlo desde el (1) primer paso?
  • ¿Cómo se maneja la concurrencia?
  • ¿Cada método agrega algo a la solicitud o simplemente valida? (diga ID de cuenta predeterminado?)

Basado en una intuición, los codificaría como métodos simples con parámetros de agregación para códigos de error.

public void DoTransaction(IErrorAgregator error, TransactionRequest request)
{
    if(!IsTransactionInCertainTimePeriod(request, error)) return;
    if(!IsTransactionAmountInUserBounds(request, error)) return;
    if(!UserHaveDefaultAccount(request, error)) return;
    bankingTransactor.PerformTransaction(request);
}

Puede ser una buena idea colocar DoTransaction en la interfaz "ITransactionValidationStragegy" y crear un supertipo de capa que contendrá el código repetitivo de validación.

Sin embargo, en este diseño, supongo que la lógica de validación se determina en el momento de la compilación.

Valera Kolupaev
fuente
2

Si su secuencia de pasos realiza principalmente tareas de validación (como parece), sin mutar las entradas, pensaría en el patrón de "Cadena de responsabilidad", como se explica en su respuesta de @pswg

Pero dado que su pregunta es un poco más genérica, me gustaría agregar también el "Proceso de canalización", ya que con este, un paso produciría una salida que se convertiría en la entrada para el siguiente paso (mutando así la entrada original) .

Aquí hay dos artículos al respecto:
Colección Pipeline por Martin Fowler
Más discusión teórica sobre el patrón

julio.g
fuente
0

Si bien los patrones ya se mencionan aquí, le sugiero que piense en cómo le gustaría usar lo mismo en su aplicación, en función de los marcos que está utilizando.

Por ejemplo, la validación que le gustaría hacer, lo más probable es que siga cambiando a medida que avance el tiempo (es posible que desee agregar una nueva validación en el futuro que restrinja las transacciones a 10 por día). Además, es posible que no desee realizar la validación antes de que su servicio comercial real o código de integración entre en vigencia. Sería bueno si puede agregar las validaciones como configurables.

En caso de que esté usando Struts, usar interceptores podría ser una buena idea. En caso de primavera, la inyección de frijoles como dependencia le brinda más flexibilidad. Mi sugerencia no es solo mirar los patrones / expresiones idiomáticas, sino también el marco que usa para construir la aplicación y ver cómo puede encajar mejor en sus requisitos desde un punto de vista futurista.

Arun
fuente
-2

Según tengo entendido, todo lo que se requiera puede ajustarse al patrón de comando como se muestra a continuación. El diseño de la clase se puede hacer de la siguiente manera.

interface Transaction{
void performAction();
}

class Banking{

void moneyValidation(){
//Validate Here
}

void timeValidation(){
//validate Here
}
}

class TimeValidation implements Transaction{

public Banking bank;

public TimeValidation (Banking bnk){
bank=bnk;
}

void performAction(){
bnk.timeValidation();
}


class MoneyValidation Implements Transaction{

public Banking bank;

public MoneyValidation(Banking bnk;){
bank=bnk;
}

void performAction(){
bnk.moneyValidation();
}
}


class Control{

private List val_list=new ArrayList();

void storeValidation(Transaction trans){
val_list.add(trans);
trans.performAction(val_list.getFirstAndRemove());
}
}

//Same for other validation classes

Su clase de Cliente contendrá el siguiente fragmento de código:

Banking bnk = new Banking();
MoneyValidation m_val = new MoneyValidation (bnk);
TimeValidation t_val = new TimeValidation (bnk);
Control ctrl = new Control();
ctrl.storeValidation(m_val);
ctrl.storeValidation(t_val);

Esto es según mi entendimiento, con el escenario que se ha dado anteriormente.

alok
fuente
Es malo porque cuando la validación de dinero falla, la validación de tiempo es inútil pero se hará de todos modos
Ewoks