2011-04-30 17 views
7

Estaba revisando un artículo de Robert C. Martin y en un lugar dio un ejemplo como este:¿Por qué deberíamos colocar las interfaces con las clases que las usan en lugar de las que las implementan?

La primera imagen muestra que hay una dependencia cíclica entre los dos paquetes. Para eliminar esta dependencia, se agrega una nueva interfaz en la segunda imagen. B implementa la interfaz y Y lo usa. Y Martin hace que el siguiente punto:

interfaces son muy a menudo se incluyen en el paquete que los utiliza, en lugar de en el paquete que las implementa.

Mi pregunta es, ¿por qué deberíamos organizar las interfaces de esta manera? ¿Cuál es el razonamiento detrás de las interfaces de empaque de esta manera? De acuerdo con las clases del Principio de cierre común que cambian juntas deben permanecer juntas. ¿Hay una interfaz más cercana a su implementador o su usuario, en términos de cambio?

enter image description here

+2

Pero las interfaces se pueden utilizar y se pueden implementar en diferentes módulos. En nuestra compañía, los almacenamos en un módulo separado que está siendo referenciado por todos ellos, esa forma en que son un módulo per se. Esto es importante para nosotros porque tenemos muchos, y me refiero a MUCHAS interfaces, y es más fácil mantener todo esto así ... aún más si tienes reglas de la compañía sobre quién puede comprometerse con alguna ruta en el repositorio. Y no todos pueden hacer cambios en las interfaces ... –

+0

Pero luego, si la interfaz cambia, tendrá muchísimos cambios extendiéndose a través de tantos módulos, ¿no? –

+0

FYI - http://martinfowler.com/eaaCatalog/separatedInterface.html. Esto pone la situación en una perspectiva más clara, creo. Es la necesidad de eludir la estructura de dependencia que puede causar una situación como esta. ¿Pero qué hay de los escenarios generales? –

Respuesta

8

Técnicamente, el usuario no está más cerca de la interfaz que el implementador. En términos de cambio, ambos tendrán que cambiar cuando la interfaz cambie.

Sin embargo, ¿por qué cambiaría la interfaz?

El usuario llama a una interfaz para que pueda ser independiente de cualquier implementador disponible. Por lo tanto, la definición de la interfaz está dictada por las necesidades del usuario.

Como el usuario dicta la definición de la interfaz, no tiene sentido cambiar la interfaz si el usuario no la necesita. Un implementador que requiera un cambio en la interfaz para acomodar la implementación debería enviar banderas rojas. ¿Por qué necesita más o más información del usuario? ¿De qué sirve eso para el usuario?

Además, el implementador "simplemente" depende de la interfaz en la medida en que necesita proporcionar implementaciones para cada uno de los métodos en la interfaz. Pero es libre de proporcionar talones vacíos, en esencia entregando un NOP a sus clientes.

Por lo tanto, las necesidades del usuario conducen cambios a la interfaz y los cambios en la unidad de interfaz cambian a los implementadores. Como tal, el usuario está funcionalmente mucho más cerca de la interfaz que el implementador. Lo cual es un buen argumento para declarar la interfaz con el usuario y no con el implementador.

+0

Impresionante. Muchas gracias, Marjan. Usted me aclaró esto perfectamente. –

+0

¡Desearía poder votar esta respuesta más de una vez! –

0

No hay razón para implementar una interfaz hasta que haya algo que lo necesita. YAGNI.

+0

Hmm. Supongamos que RCM está desarrollando un patrón o digamos que la interfaz "es" necesaria. No estoy preocupado con el patrón aquí. Estoy más preocupado por la declaración que hizo sobre la localidad de las interfaces. –

1

Normalmente utilizamos interfaces como un protocolo entre un servidor y un cliente para que el cliente sepa qué servicios están disponibles pero hay un efecto secundario para este enfoque, el cliente dependerá del servidor y por lo tanto, si algo cambió en el servidor lado que afecta la interfaz dada, el cliente también debe cambiar. Así que existe este principio entre los principios SOLID, inventado por Robert C. Martin, y que es "Dependency Inversion Principle" o "DIP", que como su nombre lo indica dice que debemos invertir la dependencia entre el cliente y el servidor para evitar cambios en el futuro . En este enfoque, el cliente dice lo que va a necesitar a través de una interfaz y el servidor debe implementarlo para servir lo que necesita, por lo tanto, ningún cambio en el servidor nos obliga a cambiar el cliente.

+0

Buen punto pero aún no está más cerca de responder: p –

0

Esto es un problema de resolviendo las dependencias cíclicas entre los componentes AB y XY. Ninguno se puede compilar sin el otro. AB está haciendo referencia a XY y XY está haciendo referencia a AB.

Robert C. Martin se appying la InversinOfControl patrón para resolver este

Ahora XY hace referencia ABInterface. ABInterface no necesita saber XY en absoluto.

Estás bien, esto viola la cohesión (lo llamaste Común Cierre Principio)

También contradice el principio KeepItSimple. La solución más simple tendría solo un componente monolítico ABXY que es mucho más difícil de mantener.

+0

Bueno, la pregunta es por qué quiere mantener la interfaz con la clase que la usa. No queremos entrar en diseños alternativos. –

2

Primero se debe decir que no hay una sola forma de desollar a un gato.

Esta metodología particular es útil al dividir un proyecto entre varios equipos de proyecto o al crear un sistema con subsistemas desacoplados. La interfaz sirve como un "contrato" entre dos subsistemas. Al colocar la interfaz en "su territorio", la parte consumidora tiene una mejor garantía de que la interfaz permanecerá sin cambios, a menos que la parte implementadora contacte a la parte consumidora para solicitar dicho cambio.

+0

+1 Buen punto. Similar a Marjan, pero aún agrega un poco a mi comprensión. –

Cuestiones relacionadas