2008-11-01 9 views
5

que tienen algún controlador de eventos en una clase de límite que gestiona un mecanismo de persistencia para una transacción genérico dado:¿Cuándo dejas de encapsular?

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 objetos SimpleTransaction y TransactionPErsistor?

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

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

¿Alguna opinión?

Saludos

+0

+1 por considerar a la gente (afortunada) que mantendrá sus objetos! –

+0

Consideraciones para su caso específico agregado, según lo solicitado. – VonC

+0

"Consideración de denominación con respecto a la cohesión de una clase" agregada a mi respuesta, según lo solicitado. – VonC

Respuesta

3

Considerando que:

  • la concept of encapsulation es sobre la definición de un contenedor, y
  • diseño orientado a objetos se basa en el concepto de paso de mensajes (invocación de métodos)

Yo diría que el 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) que ofrece 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 una exageración.

Dado que se expone a un público API mediante la creación de un nuevo objeto, la noción de prueba puede ser más fácil hacerlo 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 se define un TransactionManager, que le brinda la oportunidad de inferior de acoplamiento de los diferentes niveles de arquitectura de (GUI) frente a los datos presentes en MyBoundaryClass, y para exportar la gestión de datos en una clase dedicada.
Luego, puede probar la persistencia de los datos en el escenario de prueba independiente, centrándose especialmente en los valores límite, la falla de la base de datos y las condiciones no nominales, y así sucesivamente.

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

Como se puede argumentar que Coupling and Cohesion are two cornerstones of OO Programming, la cohesión de una nueva clase como TransactionManager se puede evaluar en términos del conjunto de acciones que llevará a cabo.

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

Si reagrupar las conductas aplicadas distintas en varios lugares diferentes en su TransactionManager, que debería estar bien, siempre y cuando su API pública representan pasos claros de lo que una transacción implica y no "cosas acerca de la transacción" como diversas 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 una TransactionManager sería para encapsular completamente la noción de transacción, lo que haría:

  • vuelto prácticamente desconocido por el resto f del sistema, y ​​reduciría el acoplamiento entre las otras clases y 'Transaction'
  • refuerzan la cohesión de TransactionManager al centrar su API alrededor de los pasos de la transacción (como initTransaction(), persistTransaction(), ...), evitando cualquier getter o setter para cualquier instancia de Transaction.
+0

+1 por el asesoramiento que se obtuvo claramente de la experiencia! –

+0

usted hace un gran punto - podría integrarse con algunas consideraciones aplicando su comentario general a mi caso/ejemplo específico? – JohnIdol

+0

Gracias por su consideración. Aunque ya tengo un TransactionPersistor, ¿quiere decir "Pero si define un TransactionManager (...)"? – JohnIdol

2

Abundando en la sugerencia de VonC, tenga en cuenta las siguientes pautas:

  • Si va a invocar las mismas funciones en otro lugar, de la misma manera, es razonable para encapsular 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.

punto de VonC sobre el API es una excelente prueba de fuego: crear las interfaces eficaces, y los objetos a menudo se hacen evidentes.

+0

Y ... +1 para las precisiones. Completaré mi respuesta – VonC

1

El nivel de encapsulado debe ser directamente relacionado con la cohesión de su objeto. Su objeto debe hacer una única tarea o dividirse en varias clases y encapsular todos sus comportamientos y propiedades.

Una regla de oro es cuando es el momento de probar su objeto. Si está realizando pruebas unitarias y se da cuenta de que está probando varias cosas diferentes (no en la misma acción de área), puede intentar dividirlas.

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

+0

¿No es TransactionManager un nombre demasiado vago? Parte del problema está relacionado con el hecho de que si ves un objeto "administrador" realmente no sabes lo que hace, entonces la cohesión de mi objeto sería bastante pobre – JohnIdol

+0

+1 para las palabras de moda y la teoría respaldada por la practicidad y una sugerencia específica y útil. ¿Dónde estaban ustedes antes de aprender de la manera difícil? :-) –

Cuestiones relacionadas