¿Cómo gestionar la responsabilidad individual cuando la responsabilidad se comparte?


10

Tengo base dos clases, Operationy Trigger. Cada uno tiene una serie de subclases que se especializan en ciertos tipos de operaciones o disparadores. A Triggerpuede desencadenar un específico Operation. Mientras que un Operationpuede ser activado por un específico Trigger.

Necesito escribir el código que asigna un dado Operationa un dado Trigger(o viceversa), pero no estoy seguro de dónde ponerlo.

En este caso, el código no pertenece claramente a una clase u otra clase. Entonces, en términos de un principio de responsabilidad única, no estoy seguro de dónde debe pertenecer el código.

Puedo ver tres opciones que funcionarían. Mientras que 1 y 2 parecen ser solo una elección de semántica, 3 representa un enfoque completamente diferente.

  1. En el gatillo, por ejemplo bool Triggers(Operation o).
  2. En la operación, por ejemplo bool TriggeredBy(Trigger t).
  3. En una clase completamente nueva que gestiona la asignación, por ejemplo bool MappingExists(Trigger t, Operation o).

¿Cómo debo decidir dónde colocar el código de mapeo compartido con respecto a un principio de responsabilidad única?

¿Cómo gestionar la responsabilidad individual cuando la responsabilidad se comparte?


Editar 1.

Entonces el código real se ve así. Todas las propiedades, son o bien un string, Guid, collection<string>, o enum. Básicamente, solo representan pequeños datos.

ingrese la descripción de la imagen aquí

Editar 2.

La razón del tipo de retorno de bool. Otra clase va a consumir una colección de Triggery una colección de Operation. Necesita saber dónde existe un mapeo entre a Triggery an Operation. Utilizará esa información para crear un informe.


¿Por qué el tipo bool?
Tulains Córdova

@ user61852 para devolver un resultado al código de llamada
James Wood

1
¿Qué hace el código de llamada con el booleano? Dependiendo de lo que responda a esta pregunta, podría tener la solución.
Tulains Córdova

@ user61852, vea mis ediciones.
James Wood

1
Entonces, ¿no tiene nada que ver con la ejecución real del disparador de la operación?
Tulains Córdova

Respuestas:


4

Lo pensaría de esta manera: cómo se determina qué Operación causa qué Trigger se dispara. Tiene que ser un algoritmo que pueda cambiar con el tiempo o evolucionar en múltiples algoritmos. Ponerlo en las clases Trigger u Operation implica que esas clases podrán manejar tales escenarios en el futuro. Tenga en cuenta que no lo veo tan simple como una asignación, ya que puede haber más.

Mi elección sería crear una clase con los métodos adecuados, como GetOperationForTrigger (Trigger t). Esto permite que el código evolucione en un conjunto de tales clases cuya elección puede depender en tiempo de ejecución u otras variables (por ejemplo, patrón de estrategia).

Tenga en cuenta que la suposición principal en esta línea de pensamiento es escribir un código mínimo (es decir, tres clases hoy) pero evitar una refactorización importante si la funcionalidad necesita ser extendida en el futuro al no suponer que siempre habrá exactamente una forma de determinar qué disparador causa qué operación.

Espero que esto ayude. Aunque la respuesta es similar a la del usuario 61852, el razonamiento es diferente. Como resultado, la implementación será diferente (es decir, tener métodos explícitos en lugar de anular iguales, por lo que la cantidad de métodos puede evolucionar con el tiempo según las necesidades).


5

He estado allí, hecho eso.

Opción # 3.

No sé qué idioma utilizará, pero utilizaré un pseudocódigo que es muy similar a Java. Si su lenguaje es C #, probablemente tenga interfaces y estructuras similares.

Tener una clase o interfaz de mapeo:

public interface Mapping {
    public void setObject1(Object o);
    public void setObject2(Object o);
    public Object getObjecto1();
    public Object getObjecto2();
}
  • Anule el equals()método Mappingpara que Mappingse puedan consultar las colecciones de si contienen una asignación determinada.
  • Los objetos especializados también deben tener equals()métodos adecuados .
  • Implemente también la interfaz Comparable, para que pueda ordenar los informes.

Ellos simplemente pueden poner un mapeo en una colección

List<Mapping> list = new ArrayList<Mapping>();
Hat hat = new Hat();
Bag bag = new Bag();
list.add(new Mapping(hat,bag));

Más tarde puedes preguntar:

// let's say you have a variable named x which is of type Mapping

if ( list.contains(x) ){
    // do some thing
}

0
  1. Divide tu código en partes más pequeñas.

Actualmente tiene la clase A que sabe acerca de la clase B y la clase B que sabe acerca de la clase A. Eso es mucho acoplamiento.

Por definición, A está haciendo al menos su propia operación Y comprobando si B debe ejecutarse. Lo contrario es cierto con B. Cualquiera que sea la clase llamada primero, debería poder ver el resultado y ver si es necesario ejecutar más cosas.

Intenta romper ese acoplamiento dividiendo tus clases en componentes más pequeños. Me gusta poner un comentario en la parte superior de cada clase explicando en inglés lo que hace. Si necesita usar palabras como AND o va sobre una o dos oraciones, entonces debe considerar desglosarlas. Como regla general, cualquier cosa después de un "y" debe estar en su propia clase

Vea también si puede definir una interfaz que cubra la funcionalidad de Trigger and Operation. Si no puede, eso es otra indicación de que su clase se está volviendo demasiado grande. También romperá el acoplamiento entre tus clases.


1
Honestamente, no estoy seguro de poder descifrar mi código aún más. He actualizado mi pregunta con las firmas de clase para que pueda ver, pero básicamente son objetos de datos bastante livianos que almacenan algunas propiedades cada uno. En términos de acoplamiento, sí, eso es un poco problemático, ya que efectivamente a Triggerestaría acoplado a a Operation. Pero así es como se ven los datos del mundo real. Están acoplados, porque hay un mapeo, por ejemplo, tienen que saber unos de otros para tener significado.
James Wood
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.