Pregunta

Tengo algún controlador de eventos en una clase de límite que administra un mecanismo de persistencia para una transacción genérica determinada:

void MyBoundaryClass::MyEventHandler(...)
{
  //retrieve stuff from the UI
  //...
  //declare and initialize trasaction to persist
  SimpleTransaction myTransaction(.../*pass down stuff*/);
  //do some other checks
  //...
  //declare transaction persistor
  TransactionPersistor myPersistor(myTransaction, .../*pass down connection to DB and other stuff*/);
  //persist transaction
  try
  {
    myPersistor.Persist();
  }
  catch(...)
  {
    //handle errors
  }
}

¿Sería mejor tener algún tipo de TransactionManager para envolver los objetos SimpleTransaction y TransactionPErsistor?

¿Hay alguna regla práctica para comprender si necesito un nivel adicional de encapsulación?

En este momento, la regla de oro que sigo es " si el método es demasiado grande, haz algo al respecto " ;. A veces es difícil encontrar el equilibrio adecuado entre procedimientos y orientado a objetos cuando se trata de manejadores de eventos de límite.

¿Alguna opinión?

Saludos

¿Fue útil?

Solución

Teniendo en cuenta que:

  • el concepto de encapsulación se trata de definir un contenedor, y
  • el diseño orientado a objetos se basa en el concepto de paso de mensajes (invocación de métodos)

Argumentaría que API es una buena indicación sobre la pertinencia de una nueva encapsulación de alto nivel (es decir, la definición de un nuevo objeto)

Si los servicios (es decir, la API) ofrecidos por este nuevo objeto son coherentes y están mejor expuestos al resto del programa cuando se reagrupan en un objeto especial, entonces, por supuesto, use un nuevo objeto.

De lo contrario, es probable que sea una exageración.

Dado que expones una API public al crear un nuevo objeto, la idea de prueba puede ser más fácil de hacer dentro de ese nuevo objeto ( y algunos otros simulacros objetos, en lugar de crear muchos objetos heredados para probar esas mismas operaciones.

En su caso, si desea probar la transacción, debe probar MyEventHandler of MyBoundaryClass para recuperar datos de la interfaz de usuario.

Pero si define un TransactionManager, le da la oportunidad de reducir el acoplamiento de diferentes niveles de arquitectura (GUI en comparación con los datos) presente en MyBoundaryClass, y exportar la administración de datos a una clase dedicada. < br> Luego, puede probar la persistencia de los datos en un escenario de prueba independiente, centrándose especialmente en los valores límite y el fallo de la base de datos, y las condiciones no nominales, etc.

El escenario de prueba puede ayudarlo a refinar la cohesión (punto destacado mencionado por Daok ) de tus diferentes objetos. Si sus pruebas son simples y coherentes, es probable que sus objetos tengan un límite de servicio bien definido.

Dado que se puede argumentar que Coupling and Cohesion son dos pilares de la programación de OO , la cohesión de una nueva clase como TransactionManager puede evaluarse en términos del conjunto de acciones que realizará.

  

Cohesivo significa que una determinada clase realiza un conjunto de acciones estrechamente relacionadas. Una falta de cohesión, por otro lado, significa que una clase está realizando varias tareas no relacionadas. [...] el software de la aplicación se volverá inmanejable a medida que más y más comportamientos se dispersen y terminen en lugares equivocados.

Si reagrupa los comportamientos implementados de otra manera en varios lugares diferentes en su TransactionManager, debería estar bien, siempre que su API pública represente pasos claros de lo que implica una transacción y no " cosas sobre la transacción " como varias funciones de utilidad. Un nombre en sí mismo no es suficiente para juzgar la cohesión de una clase. La combinación del nombre y su API pública es necesaria.

Por ejemplo, un aspecto interesante de un TransactionManager sería encapsular completamente la noción de Transacción, que sería:

  • se vuelve virtualmente desconocido por el resto del sistema, y ??reduciría el acoplamiento entre las otras clases y la 'Transacción'
  • refuerce la cohesión de TransactionManager al centrar su API alrededor de los pasos de la transacción (como initTransaction (), persistTransaction (), ...), evitando cualquier captador o definidor para cualquier instancia de Transaction.

Otros consejos

Para elaborar la sugerencia de VonC, considere las siguientes pautas:

  • Si espera invocar las mismas funciones en otros lugares, de la misma manera, es razonable encapsularlas en un nuevo objeto.

  • Si una función (o un objeto) proporciona un conjunto de recursos que son útiles individualmente, es razonable refactorizarlo en componentes más pequeños.

El punto de VonC sobre la API es una excelente prueba de fuego: cree interfaces eficaces, y los objetos a menudo se hacen evidentes.

El nivel de encapsulación debe estar directamente vinculado a la cohesión de su objeto. Su objeto debe realizar una sola tarea o debe dividirse en varias clases y encapsular todos sus comportamientos y propiedades.

Una regla de oro es cuando es hora de probar tu objeto. Si está realizando la prueba unitaria y se da cuenta de que está probando varias cosas diferentes (no en la misma área de acción) de las que podría intentar dividir.

Para su caso , lo resumiría con su idea de " TransactionManager " ;. De esta manera, el " TransactionManager " manejará cómo funciona la transacción y no " MyBoundaryClass " ;.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top