Los patrones deben usarse solo donde puedan ser la mejor solución o ayudar en la creación de una buena solución (¿está de acuerdo?).
Veo patrones de diseño estrictamente como detalles de implementación. Si documenta sus API y programas públicos en esa documentación, en general no importará (o le afectará mucho) dónde tiene patrones de diseño. Es decir, usted no dice "Tengo un patrón de puente aquí e implementaré un visitante encima". En cambio, es "esta clase tendrá implementaciones diferentes en varios sistemas operativos, por lo que se implementará utilizando un patrón de puente". Luego, cuando lo usas, eres indiferente a que se implemente como un puente, porque miras la API pública, no un patrón de puente.
¿Cuánto esfuerzo debería uno invertir en crear diseños flexibles y poco acoplados?
El acoplamiento flojo se puede lograr siguiendo un conjunto simple de reglas. Si respeta estos, su código se acoplará (más) libremente, a medida que lo escriba (es decir, cualquier esfuerzo ya forma parte del proceso de desarrollo).
Entre las reglas (no una lista exhaustiva):
- defina sus interfaces pensando (o escribiendo) el código del cliente (cómo se usará la clase), no lo que hará la clase (es decir, diseño de interfaz, no implementación)
- "dile, no preguntes"
- construir objetos a partir de partes ya creadas
- Pase al constructor los objetos reales que usará (no fábricas para los miembros, parámetros para las fábricas de los parámetros, ni nada de eso).
- SECO (si tiene dos líneas que aparecen en el mismo orden en dos lugares, extráigalas en una función separada y así sucesivamente).
- Si la creación de un objeto es una operación más compleja, implemente la creación de las partes intermedias como un método / clase de fábrica (es decir, no en el cuerpo del constructor).
- YAGNI (crea cosas como las necesites, no antes).
Estas reglas se siguen de manera diferente, según el lenguaje, la metodología de desarrollo seguida por su equipo (por ejemplo, TDD), las limitaciones de presupuesto de tiempo, etc.
Por ejemplo, en Java, es una buena práctica definir su interfaz como un interface código de cliente y escribir sobre eso (luego, instanciar la interfaz con una clase de implementación).
En C ++, por otro lado, no tiene interfaces, por lo que solo puede escribir la interfaz como una clase base abstracta; Dado que en C ++ solo usa la herencia cuando tiene un fuerte requisito para ello (y como tal evita la sobrecarga de funciones virtuales innecesarias), probablemente no definirá la interfaz por separado, solo el encabezado de la clase).
Quienes se oponen a los patrones de diseño dicen que los costos de usar estos patrones a menudo superan los beneficios.
Creo que lo están haciendo mal. Si escribe código débilmente acoplado (y SECO), la integración de patrones de diseño en él conlleva un esfuerzo adicional mínimo. De lo contrario, tendrá que adaptar su código para implementar un patrón de diseño.
Si tiene que hacer muchos cambios para implementar un patrón de diseño, su problema no es el patrón de diseño, sino que su código base es monolítico y está estrechamente acoplado. Este es un problema de diseño malo / subóptimo, no un problema de patrones de diseño.
Lo que me gustaría saber es cuánto esfuerzo debería poner en la creación de niveles adicionales de abstracción y diseños, solo para permitir que mi aplicación siga los principios de OO, como acoplamiento flojo, programación de programas a una interfaz, etc. ¿eso? ¿Cuánto esfuerzo debo poner en esto?
Sus preguntas hacen la suposición (no declarada) de que el único beneficio del acoplamiento flojo es la capacidad de implementar fácilmente patrones de diseño. No lo es.
Entre los beneficios del acoplamiento suelto están:
- refactorización y rediseño de flexibilidad
- menos esfuerzo desperdiciado
- comprobabilidad
- mayor posibilidad de reutilizar el código
- simplicidad de diseño
- menos tiempo en el depurador
... y algunos otros que no me vienen a la mente en este momento.