Al escribir código orientado a objetos, ¿debería seguir siempre un patrón de diseño?

37

¿Existe un patrón de diseño concebible para cualquier programa orientado a objetos? Pregunto esto porque recientemente vi una implementación de una Doorclase con un Lock. Formaba parte de una prueba y la respuesta decía que el código sigue el patrón Objeto nulo:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

Esto me hizo pensar: este código sigue un buen patrón de diseño a pesar de que la descripción es muy simple (esta clase está diseñando una clase de puerta con cerradura), así que si estoy escribiendo un código más complejo, ¿ siempre debería haber algún patrón de diseño que yo estoy siguiendo?

usuario2030677
fuente
51
¿Crees que podrías hablar completamente en modismos? ¿No? Entonces no deberías construir tus programas juntando patrones de diseño.
Kilian Foth
44
En su ejemplo, el patrón de objeto Nulo solo se agrega con fines académicos, no introduce "un buen diseño" en este código.
Doc Brown
44
@djechlin: en otras palabras, use el patrón de diseño de "dos palabras" :)
Michael Shaw
11
El problema es que muchas personas creen que los patrones de diseño son un sustituto del pensamiento y un sustituto de la experiencia (lo que implica una cierta cantidad de prueba y error). No puede tomar un libro lleno de patrones de diseño y armarlos como Tinker Toys para producir una aplicación con un tamaño y complejidad no triviales y una calidad decente. Incluso los programadores experimentados a menudo necesitan probar dos o tres diseños antes de encontrar uno que funcione.
Daniel R Hicks

Respuestas:

143

¿siempre debería haber algún patrón de diseño que estoy siguiendo?

Querido Dios NO!

Es decir, que puede seguir adelante y decir que cualquier código aleatorio está siguiendo un patrón aleatorio XYZ, pero eso no es más útil que yo pretendo ser el rey de mi silla de la computadora. Nadie más sabe realmente qué significa eso e incluso aquellos que lo hacen no respetarán exactamente mi reclamo.

Los patrones de diseño son una herramienta de comunicación para que los programadores puedan decirles a otros programadores lo que se ha hecho o lo que se debe hacer sin perder mucho tiempo repitiéndose. Y como son cosas que surgen muchas veces, son conceptos útiles para que los programadores aprendan "oye, hacer que XYZ siempre aparezca porque es bueno / útil".

Ellos no reemplazan la necesidad de que piensen por sí mismo, a adaptar los patrones para el problema único delante de usted, o para manejar todas las cosas inevitables que no encajan en cubos agradables.

Telastyn
fuente
55
Su primer párrafo es parte de cómo respondería esto. Algo se convierte en un patrón cuando se repite. Si se repite suficientes veces para requerir comunicación, es un Patrón y se beneficia de un nombre. Algunos incluso argumentan que un patrón solo se desarrolla porque falta algo de abstracción. La búsqueda de patrones es el camino a la infamia como miembro del aclamado Cargo Cult.
Magus
11
@ Cerad: Claro, ¡siempre y cuando prometas no escribir clases de Dios también!
yatima2975
99
John Doe - Ingeniero Técnico, Generic Code Monkey y King de su silla de computadora
hjk
1
Podría decirse que un diseño debe usar patrones cuando sea apropiado y las clases deben nombrarse como tales. Son una herramienta importante. Tener miedo de the_cult(tm) es igual de peligroso.
Gusdor
25
¡Gran respuesta! Mi única crítica es que el "Querido Dios NO!" no es lo suficientemente grande
tobyink
37

No.

Esto es lo que la Banda de los Cuatro (que originalmente popularizó los patrones de diseño) tenía que decir al respecto en su libro :

"Ninguna discusión sobre cómo usar patrones de diseño estaría completa sin unas pocas palabras sobre cómo no usarlos. Los patrones de diseño no deben aplicarse indiscriminadamente. A menudo logran flexibilidad y variabilidad al introducir niveles adicionales de indirección, y eso puede complicar un diseño y / o le cuesta algo de rendimiento. Un patrón de diseño solo debe aplicarse cuando la flexibilidad que ofrece es realmente necesaria ".

El ejemplo que muestra en realidad no hace mucho de nada (no creo que fuera para hacerlo, creo que fue solo un ejemplo). Por sí mismo, no necesita el patrón de objeto nulo. En el contexto de un programa más amplio, podría.

El enfoque equivocado es suponer que solo porque ha sido etiquetado como un "patrón de diseño" debe ser bueno, y luego buscar más lugares para incluir más patrones. Úselos cuando se ajusten al programa y realmente resuelvan un problema para usted.

Michael Shaw
fuente
77
El libro es Patrones de diseño: elementos de software orientado a objetos reutilizables por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides.
developerwjk
44
+1 Para citar realmente la fuente de los patrones de diseño.
Pharap
29

si estoy escribiendo un código más complejo, ¿siempre debería haber algún patrón de diseño que esté siguiendo?

No. Los patrones de diseño son solo eso: patrones en las relaciones entre objetos. En otras palabras, las relaciones que se usan y reutilizan con la frecuencia suficiente para que alguien diga "Oye, parece que estamos haciendo esto mucho, vamos a ponerle un nombre". La lista de patrones de diseño no se determinaron todos a la vez en el comienzo de programación orientada a objetos y luego transmitida por GOF ! Fueron descubiertos y finalmente documentados, y luego popularizados por el libro.

Dicho esto, una gran parte del beneficio de los patrones de diseño es que hacen que sea más fácil pensar en el diseño de software a un nivel superior. Le permiten dejar de preocuparse por los detalles de implementación y pensar más sobre el panorama general. En ese sentido, te liberan de las minucias, pero también pueden limitarte de la misma manera que la forma en que te expresas puede estar limitada por las palabras que conoces. Por lo tanto, puede llegar un momento en que no es un patrón de diseño para la mayor parte de lo que haces simplemente porque los patrones que sabe que son los términos en los que se piensa. Mantenga los ojos abiertos para casos en los que podría estar abusando de un patrón y en los que deba pensar más profundamente sobre mejores formas de hacer las cosas.

Además, tenga en cuenta que en la práctica a menudo no implementa un patrón de diseño determinado, sino que reconoce el patrón en algún código existente, como un marco de objetos. Conocer los patrones de diseño comunes hace que sea mucho más fácil aprender cómo se debe usar un marco porque puedes ver las relaciones entre clases en términos que ya entiendes.

Caleb
fuente
10

Los patrones de diseño tienen dos ventajas.

  1. Son fáciles de describir a otros desarrolladores, porque las personas generalmente están de acuerdo en cuáles son los patrones
  2. Suelen haber sido golpeados con bastante cuidado por nuestros predecesores, por lo que sus fortalezas y debilidades son bien entendidas.

Los objetivos de cada programa deben ser

  1. Funciona. Tiene que hacer cualquiera que sea el objetivo final, o no importa cuántos patrones de diseño use. Los patrones de diseño OO facilitan dividir el problema en partes fáciles de entender, por lo que es más fácil demostrar que funciona.
  2. Es facil de leer. Aquí es donde los patrones de diseño son agradables. Los problemas de OO que resuelven son complicados. Si los resuelve de forma "estándar", es más fácil para el próximo desarrollador
  3. Es fácil de cultivar. Casi 0 programas modernos terminan donde todos los planearon. Cada programa crece después de su lanzamiento inicial. Los patrones OO son conocidos por ser curiosamente buenos para crecer.

Dicho todo esto, tenga en cuenta que cada referencia a los patrones de diseño OO es "son simplemente buenos en el trabajo". No son perfectos, pero llenan un nicho de manera muy efectiva. Úselos cuando funcionan, evítelos cuando no.

Como ejemplo, de "código complejo", como mencionó en su pregunta, tome el lenguaje de scripting que escribí. La mayor parte es OO con patrones de diseño en todas partes. Sin embargo, cuando se trataba de escribir el recolector de basura, abandoné sin ceremonias todas las pretensiones de OO, porque las cosas particulares que tenía que hacer estaban mejor modeladas como buenas críticas antiguas. No hay un patrón OO en todo el asunto hasta que se llegó a escribir finalizadores, donde una vez más, OO comenzó a ser un modelo útil nuevamente. Sin ninguna pompa ni circunstancia, el código repentinamente volvió a usar técnicas de OO nuevamente.

Use patrones de diseño siempre que mejoren su producto; evítelos cuando empeoren su producto.

Cort Ammon
fuente
2
Creo que la última oración debería estar en la parte superior en negrita o como un resumen.
Pharap
5

Voy a cambiar un poco la tendencia, porque la respuesta es más sutil que otras respuestas. Cada clase que escriba no debe emplear un patrón de diseño, pero la mayoría de los programas no triviales que escriba probablemente sí.

Un programa no trivial sin ningún patrón de diseño indica:

  • Su programa es tan único que ninguna parte es similar a los problemas comunes que los programadores han enfrentado antes. O
  • Su programa contiene esos problemas comunes, pero los ha resuelto de una mejor manera que nadie había pensado antes.

Ambos escenarios son altamente improbables, sin ofender.

Eso no significa que el patrón de diseño deba impulsar su diseño, o que deba insertar uno indiscriminadamente porque cree que se verá mal si no lo hace. El patrón de diseño incorrecto es peor que ninguno.

Lo que significa es que debe considerar la falta de patrones de diseño en su programa general como un olor a código. Algo que te hace echar un segundo vistazo y reevaluar si tu diseño no puede ser más limpio. Si en ese momento decide dejar los patrones de diseño fuera de un programa, esa debería ser una decisión deliberada e informada, no una casualidad.

Por ejemplo, no dice: "Necesito modelar una puerta y una cerradura, ¿qué patrón de diseño debo usar?" Sin embargo, si lo diseñó primero sin usar ningún patrón de diseño, eso debería indicarle después que diga algo como: "Tengo un montón de comprobaciones nulas en este código, me pregunto si hay un patrón de diseño que pueda ayudar a administrarlos".

¿Ver la diferencia? Es una distinción sutil pero importante.

Karl Bielefeldt
fuente
55
Hay muchos más problemas comunes (y sus soluciones comunes) que los patrones de diseño. Los patrones de diseño son un subconjunto catalogado de soluciones OO comunes, no el conjunto de todas las soluciones comunes.
Michael Shaw
1
¿Podría definir qué quiere decir con "no trivial"? Tenía la impresión de que el término "no trivial" era subjetivo.
Pharap
1
Es subjetivo. Me refiero al tipo de programa que escribirías en un equipo en el trabajo, requiriendo múltiples mantenedores de manera continua.
Karl Bielefeldt
Si tienes la suerte de ver tu problema después. Cheques nulos, claro. ¿Vulnerabilidades de seguridad? ¿Otras formas insidiosas de que el programa se rompa bajo mantenimiento? ¿Problemas que solo el próximo ingeniero descubrirá? Mucho más asqueroso.
djechlin
"Necesito modelar una puerta y cerradura, ¿cuál debería ser la interfaz? ¿El rendimiento será parte del contrato? ¿Debo usar un servicio o biblioteca? ¿Cómo se pasarán los recursos?" debe preguntarse todo, y debe tener respuestas que básicamente se consideran patrones de diseño.
djechlin
4

Pregunta rota Permíteme darte una definición novedosa de patrón de diseño que solucionaría muchos daños liberados por GoF: un patrón de diseño es una buena práctica de codificación . Eso es.

Cualquier módulo razonablemente complejo tendrá varios patrones de diseño. Cada vez que guarde en caché, probablemente sea un patrón de peso mosca, pero no voy a revocar su grado de programación si no lo llama así. Cada vez que tiene una devolución de llamada, está en algún tipo de patrón de evento / incendio / devolución de llamada. etc. Si tiene la palabra "estática", tiene un singleton. Si tiene un constructor estático, tiene un patrón de fábrica. Si se pasa un recurso a su módulo, está utilizando la inyección de dependencia.

"Patrón de diseño" es un término roto poco popularizado por GoF, lo que hace que parezca que todos los patrones están en el mismo nivel o debe usar el médico recomendado de 3 a 5 por clase. Cada vez que haces algo bien que alguien más hizo bien, es un patrón de diseño . A for(;;)es un patrón común utilizado para representar un bucle infinito, por ejemplo.

No deberías intentar aprender un montón de patrones de diseño. ¡El conocimiento de programación no está indexado por patrones de diseño! Por el contrario , debe aprender a escribir un buen código leyendo libros, blogs y asistiendo a conferencias en su campo. Por ejemplo, si ya está usando la inyección de dependencia pero simplemente no la ha etiquetado, podría beneficiarse de usar siempre DI o usar un marco IoC. O bien, si tiene problemas para codificar correctamente en eventos y devoluciones de llamada, aprenda Haskell para que esté familiarizado con los patrones de diseño funcionales y se vuelva fácil.

Y si toda su clase se lee como algo importante que alguien más hizo bien, ¿por qué reinventan la rueda? Solo usa sus cosas.

djechlin
fuente
2
¿En qué idioma es for(;;)idiomático? Probablemente ese no sea el mejor ejemplo de algo que alguien hizo "bien".
Telastyn
1
@Telastyn C, C ++, Java, Javascript, C #.
djechlin
2
Nunca he visto a nadie preferir eso sobre while(true)(o while(1)) en C, C ++, Java o C # en mis más de 20 años de programación.
Telastyn
1
@Telastyn stackoverflow.com/a/2611744/1339987 fwiw Empecé a preferir while (verdadero) porque me parece más legible.
djechlin
1
Siempre uso para (;;). Sin ninguna razón en particular, probablemente lo leí en alguna parte. Me gusta el hecho de que no hay variables o constantes involucradas. De todos modos, @Telastyn ahora has conocido a alguien .
Ant
0

Siempre debe seguir los principios de diseño de OO (p. Ej., Modularidad, ocultación de información, alta cohesión, etc.). Los patrones de diseño son un nicho relativamente refinado de los principios de diseño de OO, especialmente si considera el principio KISS .

Los patrones son soluciones a problemas comunes de diseño. Estos problemas provienen de uno de dos lugares (o una combinación de ambos): el espacio del problema (por ejemplo, el software para administrar los Recursos Humanos en una empresa) y el espacio de la solución . Un programa OO es una instancia dentro del espacio de la solución (por ejemplo, una de las muchas formas en que podría diseñar un programa OO para facilitar la gestión de recursos humanos).

No es tan fácil saber cuándo usar un patrón. Algunos patrones son de bajo nivel, más cercanos a la codificación y al espacio de solución (por ejemplo, Singleton, objeto nulo, iterador). Otros están motivados por los requisitos en el espacio del problema (por ejemplo, Patrón de comando para admitir deshacer / rehacer, Estrategia para admitir múltiples tipos de archivos de entrada / salida).

Muchos patrones provienen de la necesidad de admitir variaciones del software en el futuro. Si nunca necesita hacer esas variaciones, un patrón podría estar sobrediseñado. Un ejemplo sería utilizar el patrón Adaptador para trabajar con la base de datos de recursos humanos externa existente. Decide aplicar el Adaptador porque la base de datos actual funciona con Oracle y es posible que desee admitir NoSQL en el futuro. Si NoSQL nunca llega a su organización, ese código de Adaptador podría ser inútil. Ver YAGNI . El soporte para variaciones que nunca llegan es el mal uso de un patrón de diseño

Fuhrmanator
fuente
0

Los patrones son soluciones comunes a problemas comunes. Siempre estamos siguiendo algunos patrones, los patrones de GoF abordan los más recurrentes. Eso, tener una comprensión y un enfoque compartidos conocidos por los ingenieros de software.

Dicho esto, mi respuesta es no, pero sí, siempre estás siguiendo algún patrón propio. Como bien dice el GoF:

El patrón de una persona es el bloque de construcción primitivo de otra persona.

Gran cita.

Syed Priom
fuente
Esto no parece ofrecer nada sustancial sobre los puntos formulados y explicados en 7 respuestas anteriores
mosquito
Multa. Tenga en cuenta que hice un punto general ... es aplicable a los patrones de diseño como una discusión teórica.
Syed Priom
"Este sitio se trata de obtener respuestas . No es un foro de discusión ..." ( visita )
mosquito
Respondí la pregunta. Gracias. Esta conversación termina aquí.
Syed Priom
@gnat es muchísimo más conciso, sin embargo.
djechlin
0

Cuando escribo código, no planeo usar deliberadamente tantos patrones de diseño como pueda. Pero, supongo, inconscientemente, cuando tengo un problema de codificación, uno de los patrones de diseño parece encajar, y simplemente lo uso. Y a veces nada cabe. Lo que es más importante para mí es escribir código que haga el trabajo y sea fácil de mantener y crecer.

Aquí hay un artículo sobre la aplicación de los principios de OOD utilizando patrones de diseño, y también tiene ejemplos de código (en C ++). Muestra cómo y cuándo aplicar algunos de los patrones de diseño para escribir código limpio.

agua de rosas
fuente
2
Ese artículo fue escrito ayer mismo; ¿Estás afiliado al blog? Si es así, por favor revele esa afiliación .
Martijn Pieters