low loosy loose high espaƱol coupled and design coupling

design - loose - loosy coupled



Acoplamiento suelto versus ocultamiento de informaciĆ³n y facilidad de cambio (10)

Solo estoy leyendo Code Complete por Steve McConell y estoy pensando en un Example que da en una sección sobre acoplamiento flexible. Se trata de la interfaz de un método que calcula el número de días feriados para un empleado, que se calcula a partir de la fecha de entrada del empleado y sus ventas. El autor sugiere a tener fecha de entrada y ventas como los parámetros del método en lugar de una instancia del empleado:

int holidays(Date entryDate, Number sales)

en lugar de

int holidays(Employee emp)

El argumento es que esto desacopla al cliente del método porque no necesita saber nada sobre la clase Employee.

Dos cosas vinieron a mi mente:

  1. Proporcionar todos los parámetros necesarios para el cálculo rompe la encapsulación. Muestra los aspectos internos del método sobre cómo se calcula el resultado.

  2. Es más difícil cambiar, por ejemplo, cuando alguien decide que también se debe incluir la edad del empleado en el cálculo. Uno debería cambiar la firma.

¿Cual es tu opinion?


La mejor manera desacoplada es definir una interfaz IHolidayable

Este tipo de declaración general realmente me molesta. Solo porque use una interfaz NO significa que desacople nada automáticamente. Si su clase de empleado implementa una interfaz para calcular vacaciones, cualquier código que llame al método seguirá llamando al mismo método. En el peor de los casos, el código de llamada lo hará mediante el acceso directo a un objeto de empleado, no a una referencia de interfaz de IHolidayable, en cuyo caso solo empeoró la situación (porque ahora también hay un acoplamiento más sutil entre la interfaz y cualquier clase que Impleméntalo).

Las interfaces pueden ayudar a desacoplar, pero no lo hacen automáticamente , e incluso cuando lo hacen, no son necesariamente una mejor solución que una clase abstracta (o alguna otra antecesora).


Al final, el acoplamiento flojo gana. Desde el acoplamiento alto a bajo, hay varias clases de acoplamiento:

  1. Acoplamiento de contenido (alto): Un módulo modifica o depende del funcionamiento interno de otro módulo
  2. Acoplamiento común: dos módulos comparten los mismos datos globales (p. Ej., Una variable global). Cambiar el recurso compartido implica cambiar todos los módulos que lo usan.
  3. Acoplamiento externo: dos módulos comparten un formato de datos impuesto externamente, un protocolo de comunicación o una interfaz de dispositivo.
  4. Acoplamiento de control: un módulo que controla la lógica de otro, pasándole información sobre qué hacer (por ejemplo, pasar un indicador de qué hacer).
  5. Acoplamiento de sello (acoplamiento estructurado de datos): cuando los módulos comparten una estructura de datos compuesta y utilizan solo una parte de ella, posiblemente una parte diferente (por ejemplo, pasar un registro completo a una función que solo necesita un campo).
  6. Acoplamiento de datos: cuando los módulos comparten datos a través de, por ejemplo, parámetros. Cada dato es una pieza elemental, y estos son los únicos datos que se comparten (por ejemplo, pasar un número entero a una función que calcula una raíz cuadrada).
  7. Acoplamiento de mensajes (bajo): los módulos no son dependientes entre sí, sino que usan una interfaz pública para intercambiar mensajes sin parámetros (o eventos, ver Paso de mensajes ).
  8. Sin acoplamiento: los módulos no se comunican entre sí.

Al pasar en Employee está el acoplamiento de Sello, que está más acoplado que el acoplamiento de Datos. Si realmente piensas en la facilidad de la modificación, el bajo acoplamiento es mejor porque tienes menos de qué preocuparte por los efectos secundarios no deseados. Supongamos que quiere cambiar la estructura de la clase Employee . Ahora debe verificar la implementación real de la función vacaciones para asegurarse de que no rompa las matemáticas.

La mejor manera desacoplada es definir una interfaz IHolidayable , pero eso es una exageración para esta situación.


  1. Esto no está rompiendo la encapsulación. Romper la encapsulación revelaría los métodos internos que usa para calcular las vacaciones. Proporcionar los parámetros de inicio es lo que define la API.

  2. La API podría mejorarse para permitir tales cambios; sin embargo, la mayoría de los enfoques sugieren que debe diseñar para cumplir con los requisitos actuales y no exceder el diseño para cambios imprevistos (diseño para el cambio, pero no intente predecir el cambio). Es mejor implementar lo que necesita ahora y refactorizarlo más adelante si es necesario.

En mi opinión, es mejor planear el cambio desacoplando y encapsulando tanto como sea posible para que la refactorización se pueda hacer lo más fácilmente posible. Intentar predecir con anticipación todos los escenarios posibles termina con un sistema inflado excesivamente diseñado.


1) Proporcionar parámetros no rompe la encapsulación. Simplemente muestra que estos parámetros se usan para calcular vacaciones. El "CÓMO" todavía está oculto dentro del método.

2) El método de vacaciones no debe formar parte de la clase Empleado.


A diferencia de otros mensajes, estoy de acuerdo con usted en que esto rompe la encapsulación. No es la encapsulación de una clase, sino del concepto de calcular las vacaciones. Si desea cambiar la forma en que funciona este cálculo en el futuro, y aún así evitar un acoplamiento estricto, le sugiero que haga de Employee una interfaz. Si esto todavía está muy unido al empleado porque cree que las vacaciones pueden necesitar calcularse para otras cosas, entonces podría tener una interfaz GetsHolidays de la cual el empleado heredará.

Por supuesto, la implicación de la solución que elija dependerá de qué tan serio considere que son los problemas de acoplamiento y encapsulación. Consideraría que las soluciones originales son aceptables en muchas situaciones, de ser simple, si es posible.


Diría que uno de los principales beneficios del acoplamiento flexible es la facilidad de cambio. Los tipos débilmente acoplados pueden cambiar independientemente el uno del otro, así que no entiendo tu "vs" en la pregunta.

Además, no diría que rompes la encapsulación proporcionando parámetros para el método. Puede implementar una Sum(int a, int b) todas formas, pero debe decirme (como usuario) que espera dos números.


Los problemas que veo con su argumento número 2 son

  1. está asumiendo que cada valor necesario proviene de una instancia de empleado. Esto de ninguna manera es siempre verdad. Por ejemplo, supongamos que debe tener en cuenta el estado financiero de la empresa para calcular la cantidad de "días festivos adicionales" que le da a cualquier empleado. ¿Agregaría información del estado financiero a la clase de empleado para evitar cambiar la firma?

  2. Cambiar una firma no es necesariamente "más difícil", especialmente en estos días de herramientas que resaltarán cada lugar de llamada con solo hacer clic en un botón.

Y el principal problema con su argumento número 1 es que simplemente no rompe la encapsulación como todos han dicho. Estás mostrando el qué, no el cómo, de qué se trata la encapsulación.


int holidays(Employee emp)

En este caso, solo un empleado puede usar la función en cuestión ...


Para mí, la respuesta "correcta" se reduce a si está definiendo una API de alto nivel o de bajo nivel al crear esta función. Una API de bajo nivel pone la flexibilidad por encima de la conveniencia para cualquier caso particular y argumenta para las int holidays(Date entryDate, Number sales) . Una API de alto nivel está diseñada para hacer una cosa bien con la mayor comodidad posible para el cliente. Esto aboga por los int holidays(Employee emp) porque requiere menos texto repetido por parte de la persona que llama (extrae la fecha y las ventas de la clase Employee) y es menos detallado.


int holidays (IHolidayInfo obj)

Es posible que sea una forma. En este caso, cualquier objeto que implemente IHolidayInfo podría usar la función "vacaciones". Solo una alternativa