Patrones de diseño arquitectónico. Patrones de diseño

En esencia, los patrones son patrones de diseño ordinarios. Tomado prestado de arquitectos comunes (aquellos que se ocupan de los edificios). El punto es simple. En el trabajo de un arquitecto hay tareas que pueden resolverse convenientemente de una o más formas comprobadas.

Por analogía, el diseño de software tiene sus propios problemas arquitectónicos, como dividir una aplicación en componentes/módulos, organizar dependencias entre ellos, distribuir responsabilidades funcionales, etc. Como señalaron inteligentemente los autores del libro de esta banda de cuatro (La "Banda de los Cuatro"), en nuestra industria también es posible identificar un cierto número de plantillas estándar, probadas en la práctica, para no pisar el rastrillo. que otros ya han pasado por alto.

La esencia de comprender los patrones es comprender en qué situaciones es correcto utilizar un patrón de diseño particular y aplicarlo correctamente. Es importante comprender que la fórmula “cuantos más patrones pueda incluir en mi aplicación, mejor” es incorrecta. Deben utilizarse con prudencia y sólo cuando sean realmente necesarios. Además, los patrones se vuelven obsoletos y se convierten en antipatrones a medida que se desarrolla la tecnología (que en nuestro campo lo hace más que rápidamente). Y, por supuesto, existen plantillas generalmente aceptadas y otras que se utilizan con éxito en círculos reducidos.
Aquí también debes comprender que esto no es una especie de dogma, como 10 patrones de diseño sagrados :)

Para comprender dónde se necesitan, se necesita experiencia. Es decir (estoy personalmente convencido) de que sólo un número extremadamente limitado de personas puede aprender de los errores de los demás. Todos los demás tienen que resolverlo por su cuenta :)

Daré los siguientes consejos para estudiar patrones:

1) Lea un par de libros para comprender qué tipo de animal es y con qué se come. Puede tomar una de las variaciones del libro GoF o algunos derivados para su pila de desarrollo; familiarícese con las principales plantillas populares. Inmediatamente después, recomendaría leer el libro "El sabor amargo de Java" (Bruce Tate), que trata sobre antipatrones. Esto es para comprender las desventajas de usarlos. Me gustó y creo que me salvó de muchos problemas. Lo que hay en el ejemplo de Java no tiene importancia. Estamos hablando de plantillas, por lo que será fácil de entender para los representantes de otras pilas (entre las que me incluyo) de todos modos.

2) Trate de darse cuenta de si alguna vez ha encontrado algo en su trabajo que sea o pueda convertirse fácilmente en uno de los patrones. Donde fue posible aplicar el concepto correctamente y donde solo hubo problemas debido a esto.

3) En nuevos proyectos, mantenga en su cabeza el conocimiento obtenido de las plantillas; de repente le resultará útil.

En última instancia, ya sea que conozca los patrones o no, con la experiencia se llega a comprender qué arquitectura será correcta y cuál no. Cómo hacerlo conveniente y cómo no. Y no importa cómo lo llames.

Incluso recomendaría abordar el desarrollo de la sabiduría arquitectónica de TI desde el otro lado, desde el lado de los requisitos no funcionales o las llamadas "-ilidades", hay muchos de ellos. Aquí se describen 7 piezas. En general, hay decenas de ellos.

Entre otros, como mantenibilidad (soporte de código simple), escalabilidad (escalabilidad), extensibilidad (extensibilidad), disponibilidad (estabilidad), etc. Si, al diseñar su aplicación, piensa en estas "habilidades" y trata de proporcionarlas en la medida necesaria para el proyecto, entonces, como regla general, su aplicación tendrá una arquitectura excelente. Al mismo tiempo, los patrones de diseño aparecerán de forma sucinta por sí solos.

Dado que la idea de utilizar plantillas es un intento de ingenieros de software experimentados de dar una docena de recetas preparadas a los menos experimentados, de modo que hasta que aprendan a cocinar "deliciosas gachas", no cocinen algo completamente no comestible. :) Aprende a “cocinar”, entiende -ilites :) y todo irá bien

Al crear sistemas de software, los desarrolladores a menudo se enfrentan al problema de elegir determinadas soluciones de diseño. En estos casos, los patrones vienen al rescate. El hecho es que es casi seguro que problemas similares ya se han resuelto antes y ya existen soluciones elegantes y bien pensadas, recopiladas por expertos. Si estas soluciones se describen y sistematizan en catálogos, serán accesibles para desarrolladores menos experimentados que, después de estudiarlas, podrán utilizarlas como plantillas o muestras para resolver problemas de una clase similar. Los patrones describen con precisión soluciones a problemas tan repetitivos.

El concepto de creación de software utilizando patrones es sin duda muy importante, pero relativamente joven, por lo que quizás todavía no existe una definición clara de qué es un patrón. Esto se evidencia en los debates en curso en la literatura popular y en foros relevantes en Internet.

Por ejemplo, ¿deberían considerarse patrones los algoritmos y las estructuras de datos? Hay opiniones encontradas sobre este tema. Según uno de ellos, los algoritmos son patrones computacionales, y la conocida monografía fundamental de Donald Knuth "El arte de programar" es esencialmente un catálogo de tales patrones. Según otra opinión, los algoritmos no son patrones, ya que los problemas que resuelven son demasiado pequeños (operan con conceptos tales como complejidad computacional y consumo de recursos) y el área de solución está bien definida. Los patrones resuelven problemas de mayor escala, mientras que el patrón no proporciona una solución específica, sino un camino determinado hacia una solución, y elegir el patrón correcto no es una tarea trivial, que requiere que el arquitecto tenga intuición, experiencia y cierta creatividad.

Clasificación de patrones

Debido a la popularidad del catálogo GoF, los patrones de diseño a menudo se refieren a todo tipo de patrones de la industria del software, lo cual no es del todo correcto. En el campo del desarrollo de sistemas de software, existen muchos patrones que difieren en alcance, escala, contenido y estilo de descripción. Por ejemplo, dependiendo del ámbito de aplicación, existen patrones tales como patrones de análisis, diseño, pruebas, documentación, organización del proceso de desarrollo, planificación de proyectos y otros. Actualmente, los patrones más populares son los patrones de diseño. Una de las clasificaciones comunes de tales patrones es la clasificación según el grado de detalle y el nivel de abstracción de los sistemas considerados.

Los patrones se dividen en las siguientes categorías:

  • Patrones arquitectónicos
  • Patrones de diseño
  • Modismos

Los patrones arquitectónicos, al ser los patrones de más alto nivel, describen el diagrama estructural del sistema de software en su conjunto. Este diagrama identifica los componentes funcionales individuales del sistema, llamados subsistemas, así como las relaciones entre ellos. Un ejemplo de patrón arquitectónico es el conocido paradigma de programación modelo-vista-controlador (MVC). A su vez, los subsistemas pueden estar formados por unidades arquitectónicas de nivel inferior.

Los patrones de diseño describen patrones para detallar los subsistemas de software y las relaciones entre ellos, mientras que no afectan la estructura del sistema de software en su conjunto y permanecen independientes de la implementación del lenguaje de programación. Los patrones GoF entran en esta categoría. Los patrones de diseño para sistemas orientados a objetos se entienden como descripciones de la interacción de objetos y clases adaptadas para resolver un problema de diseño general en un contexto específico. En la literatura en ruso, suele haber varias opciones de traducción para los patrones de diseño de nombres originales: patrones de diseño, plantillas de diseño, muestras. Aquí se utiliza principalmente la primera opción, a veces la segunda.

Los modismos, al ser patrones de bajo nivel, abordan cuestiones relacionadas con la implementación de un problema, teniendo en cuenta las características de un lenguaje de programación determinado. Además, a menudo los mismos modismos parecen diferentes para diferentes lenguajes de programación o no tienen ningún sentido. Por ejemplo, en C++, se pueden utilizar punteros inteligentes para eliminar posibles pérdidas de memoria. Un puntero inteligente contiene un puntero a una sección de memoria asignada dinámicamente que se liberará automáticamente cuando salga del alcance. En el entorno Java, este problema simplemente no existe, ya que utiliza la recolección automática de basura. Normalmente, para utilizar modismos es necesario tener un conocimiento profundo del lenguaje de programación que se utiliza. Cabe señalar que en el área de software existen otro tipo de patrones que no están relacionados con el diseño en general, por ejemplo, patrones de análisis, pruebas, documentación, etc.

Tipos de patrones de diseño

Patrones generativos

  • Fábrica abstracta- una clase que representa una interfaz para crear componentes del sistema.
  • Método de fábrica- define una interfaz para crear un objeto, pero deja que las subclases decidan qué clase crear una instancia.
  • Prototipo- define una interfaz para crear un objeto mediante la clonación de otro objeto en lugar de crearlo mediante un constructor.
  • Constructor- una clase que representa una interfaz para crear un objeto complejo.
  • Semifallo- una clase que sólo puede tener una instancia.
  • Inicialización diferida- un objeto que se inicializa durante la primera llamada.

Patrones estructurales

  • Adaptador- un objeto que proporciona interacción entre otros dos objetos, uno de los cuales utiliza y el otro proporciona una interfaz incompatible con el primero.
  • Compuesto- un objeto que combina objetos similares a él mismo.
  • Decorador o Envoltorio (Decorador)- una clase que amplía la funcionalidad de otra clase sin utilizar herencia.
  • Fachada- un objeto que abstrae el trabajo con varias clases, combinándolas en un solo todo.
  • Punto de entrada único (controlador frontal)- proporciona una interfaz unificada para las interfaces del subsistema. Front Controller define una interfaz de alto nivel que hace que el subsistema sea más fácil de usar.
  • Diputado (Apoderado)- un objeto que media entre otros dos objetos y que implementa/restringe el acceso al objeto al que se accede a través de él.

Patrones de comportamiento

  • Comando, Acción, Transacción (Comando)- representa acción. El objeto de comando contiene la acción en sí y sus parámetros.
  • Estrategia- tiene como objetivo definir una familia de algoritmos, encapsular cada uno de ellos y garantizar su intercambiabilidad.
  • Método de plantilla- define la base del algoritmo y permite a los herederos redefinir algunos pasos del algoritmo sin cambiar su estructura en su conjunto.
  • Observador, oyente- define una dependencia de uno a muchos entre objetos de tal manera que cuando el estado de un objeto cambia, todos los que dependen de él son notificados de este evento.
  • cadena de responsabilidad- diseñado para organizarse en un sistema de niveles de responsabilidad.

Dé un ejemplo de un patrón de diseño: una de las solicitudes más populares durante las entrevistas. Expliquemos los patrones generativos en términos simples.

Patrón del patrón inglés: muestra, plantilla. En programación, este concepto implica el uso de un enfoque o algoritmo específico que ya existe para resolver un problema en una situación determinada.

Quieres crear un coche, pero no sabes por dónde empezar. ¿Cuantas ruedas debe tener? 3, 4, 5? No lo sabes con seguridad porque nunca antes has diseñado un coche. Afortunadamente, las personas anteriores a usted han estado haciendo esto durante décadas y saben con certeza que su versión específica del automóvil requerirá una base de 4 ruedas. No es necesario experimentar y construir un triciclo para ver que no funciona.

Los patrones no están ligados a un lenguaje de programación específico, son simplemente un enfoque de diseño.

Patrones generativos

Estos son patrones que crean objetos o permiten el acceso a los existentes. Los patrones generativos son aquellas plantillas a partir de las cuales puedes crear un coche y hacerlo de la mejor manera.

Semifallo

Digamos que necesitamos organizar una línea de comunicación entre todos los residentes de la ciudad. Alternativamente, podemos simplemente tender el cable desde la casa de un residente a otra. Pero un sistema de este tipo no escalará muy bien; para agregar un nuevo residente a la red, será necesario volver a tender el cable a cada uno de los antiguos. Reparar los acantilados tampoco será la tarea más sencilla.

Aquí es donde resulta útil el patrón "Único". La única unidad en este caso será la central telefónica y por ella pasarán todas las líneas de comunicación. Para añadir un nuevo residente, sólo necesitas tender un cable desde su casa hasta la estación.

Pero lo principal de una sola estación es que una vez que la creas, puede ser utilizada por tantas personas como quieras. La cuestión es que cuando diga: "Necesito una central telefónica", la respuesta no será: "Necesitamos construir una nueva", sino "Está ubicada allí".

Registro (registro, diario de asientos)

Este patrón está diseñado para almacenar registros que se colocan en él y devolver registros que se le solicitan. Si volvemos al ejemplo de la central telefónica, será un registro en relación a los números de teléfono de los residentes.

Otro ejemplo de registro único es la contabilidad. La empresa no crea contabilidad cada vez que la necesita. Al mismo tiempo, el departamento de contabilidad almacena registros de todos los empleados de la empresa, como en un registro.

Multiton (grupo individual)

Esencialmente, este patrón es un registro de singletons, cada uno de los cuales tiene un nombre mediante el cual se puede acceder.

Grupo de objetos

Este patrón, como el anterior, contiene un conjunto de objetos, pero no todos deben ser únicos.

Fábrica

Factory es un nombre bastante preciso para este patrón. Cuando necesitas un paquete de jugo, te comunicas con la fábrica con la solicitud correspondiente, ella, a su vez, copia la norma y te entrega una copia de la misma. Lo que sucede dentro de la fábrica y cómo sucede no te molesta.

Además, las fábricas suelen crearse para producir un solo tipo de producto. Es decir, no se recomienda crear una fábrica para la producción de paquetes de jugo, teniendo en cuenta la posibilidad de crear neumáticos para automóviles.

Constructor (constructor)

Un constructor es muy similar a una fábrica, pero en lugar de copiar una plantilla, el constructor contiene en sí mismo todo el complejo conjunto de acciones necesarias para la producción. Digamos que en una fábrica de zumo de naranja sólo puedes pedir zumo de naranja, mientras que a un constructor puedes pedirle savia de abedul y él se encargará tanto del contenido del paquete como de las pegatinas e inscripciones correspondientes, que también podrás cambiar. .

Prototipo

Este patrón es similar a una fábrica, pero la fábrica está en el objeto mismo. Por ejemplo, tienes una bolsa de jugo vacía en tus manos y dices: "Quiero jugo de piña". El paquete a su vez se copia a sí mismo y se llena de jugo de piña.

En este caso, el paquete es un prototipo y crea otros objetos a partir de él, con los parámetros que requieras.

Método de fábrica

Este patrón es la base de la fábrica. De hecho, cuando creas un programa, lo primero que creas es un método de fábrica y, en base a él, se crean fábricas.

Digamos que una fábrica produce paquetes con diferentes jugos. Podemos hacer nuestra propia línea de producción para cada tipo de jugo, pero esto no es efectivo. Es más conveniente hacer una línea para la producción de paquetes básicos e introducir la separación solo en la etapa de llenado del jugo, que podemos determinar simplemente por el nombre del jugo.

Para hacer esto, creamos un departamento principal para la producción de paquetes básicos y advertimos a todos los subdepartamentos que deben producir el paquete de jugo deseado con un simple "DEBE" (es decir, cada subdepartamento debe implementar el patrón "método de fábrica"). Por lo tanto, cada subdepartamento gestiona únicamente su propio tipo de zumo y reacciona a la palabra “Must”.

Ahora, si necesitamos un paquete de jugo de plátano, simplemente le diremos al departamento de jugo de plátano: “Entendido”, y ellos, a su vez, le dirán al departamento principal de empaque de jugo: “Produzca su paquete habitual y coloque este jugo allí. "

Inicialización diferida

Digamos que trabaja en el departamento de contabilidad y tiene que preparar un "informe de pago" para cada empleado. Puede elaborar este informe para todos los empleados al comienzo de cada mes, pero es posible que algunos informes no sean necesarios y luego lo más probable es que utilice la "inicialización retrasada", es decir, preparará este informe solo cuando lo solicite la gerencia. (una entidad de nivel superior). Sin embargo, la dirección puede decir en cualquier momento que ya tiene este informe, pero si está listo o no, no lo saben ni deberían saberlo. Este patrón se utiliza para optimizar los recursos.

inyección de dependencia

Si necesitamos contratar a una nueva persona, es posible que no creemos nuestro propio departamento de RRHH, sino que introducimos una dependencia de la empresa de contratación. Ella, a su vez, a petición nuestra "necesitamos una persona", trabajará ella misma como departamento de personal o buscará otra empresa que brinde estos servicios.

La “inyección de dependencia” le permite cambiar e intercambiar partes individuales del programa sin perder la funcionalidad general.

Última actualización: 31/10/2015

¿Qué son los patrones de diseño? Un patrón representa una forma específica de construir código de programa para resolver problemas de diseño comunes. En este caso, se supone que existe un cierto conjunto de problemas generales formalizados que ocurren con bastante frecuencia, y los patrones proporcionan un conjunto de principios para resolver estos problemas.

Aunque la idea de los patrones como una forma de describir soluciones a problemas comunes en el campo del diseño apareció hace bastante tiempo, su popularidad comenzó a crecer en gran parte gracias al famoso trabajo de cuatro autores: Erich Gamma, Richard Helm, Ralph Johnson. , John Vlissides, que se llamó "Patrones de diseño: elementos de software reutilizable orientado a objetos" (en ruso conocido como "Técnicas de diseño orientadas a objetos. Patrones de diseño") y que fue publicado en 1994. Y al propio equipo de autores a menudo se le llama la “Banda de los Cuatro” o la Banda de los Cuatro, o GoF para abreviar. Este libro fue esencialmente el primer intento a gran escala de describir métodos comunes de diseño de programas. Y con el tiempo, el uso de patrones empezó a considerarse una buena práctica de programación.

¿Qué nos aporta el uso de patrones? Al escribir programas, podemos formalizar el problema en forma de clases y objetos y las relaciones entre ellos. Y aplica uno de los patrones existentes para resolverlo. Como resultado, no necesitamos inventar nada. Ya tenemos una plantilla preparada y solo necesitamos aplicarla en un programa específico.

Además, los patrones, por regla general, no dependen del lenguaje de programación. Sus principios de aplicación serán similares en C#, Jave y otros lenguajes. Aunque dentro de esta guía hablaremos de patrones en el contexto del lenguaje C#.

Pensar en patrones también facilita el desarrollo de programas en grupos. Conocer el patrón de diseño utilizado y sus principios básicos facilitará que otro programador comprenda y utilice su implementación.

Al mismo tiempo, no debes usar patrones por el bien de los patrones en sí. Un buen programa implica el uso de patrones. Sin embargo, los patrones no siempre simplifican y mejoran el programa. Su uso injustificado puede provocar complicaciones en el código del programa y una disminución de su calidad. El patrón debe ser una forma justificada y eficaz de resolver el problema.

Hay muchos patrones diferentes que resuelven diferentes problemas y realizan diferentes tareas. Pero según su acción, se pueden combinar en varios grupos. Veamos algunos grupos de patrones. La clasificación de patrones básicos se basa en el propósito o las tareas que realiza un patrón en particular.

Patrones generativos

Los patrones generativos son patrones que abstraen el proceso de creación de instancias o, en otras palabras, el proceso de generación de clases y objetos. Entre ellos destacan los siguientes:

    Constructor

    Prototipo

    Semifallo

Otro grupo de patrones - patrones estructurales- examina cómo las clases y los objetos forman estructuras más grandes: clases y objetos que son de naturaleza más compleja. Estas plantillas incluyen:

    Adaptador

    Puente

    Compuesto

    Decorador

    Fachada

    peso mosca

    Diputado (Apoderado)

El tercer grupo de patrones se llama conductual: definen algoritmos e interacciones entre clases y objetos, es decir, su comportamiento. Entre dichas plantillas se encuentran las siguientes:

    Dominio

    Intérprete

    Iterador

    Mediador

    Guardián (recuerdo)

    Observador

    Estado

    Estrategia

    Método de plantilla

    Visitante

Existen otras clasificaciones de patrones dependiendo de si el patrón pertenece a clases u objetos.

Los patrones de clase describen las relaciones entre clases a través de la herencia. Las relaciones entre clases se determinan en tiempo de compilación. Estos patrones incluyen:

    Método de fábrica

    Intérprete

    Método de plantilla

    Adaptador

Otra parte de los patrones. patrones de objetos describir relaciones entre objetos. Estas relaciones ocurren en tiempo de ejecución y, por lo tanto, son más flexibles. Los patrones de objetos incluyen lo siguiente:

    Fábrica abstracta

    Constructor

    Prototipo

    Semifallo

    Puente

    Compuesto

    Decorador

    Fachada

    peso mosca

    Diputado (Apoderado)

    cadena de responsabilidad

    Dominio

    Iterador

    Mediador

    Guardián (recuerdo)

    Observador

    Estado

    Estrategia

    Visitante

Y estos son sólo algunos de los patrones principales. En general, existen muchos más patrones de diseño diferentes. Algunos de ellos apenas están comenzando a usarse, otros son actualmente populares y algunos ya son menos comunes que antes.

Y en esta guía veremos los patrones y principios más básicos y comunes de su uso en relación con el lenguaje C#.

¿Cómo elegir el patrón correcto?

En primer lugar, al resolver un problema, es necesario identificar todas las entidades utilizadas y las conexiones entre ellas y abstraerlas de la situación específica. Luego hay que ver si la forma abstracta de resolver el problema encaja en un patrón determinado. Por ejemplo, la esencia del problema que se está resolviendo puede ser la creación de nuevos objetos. En este caso, podría valer la pena observar los patrones generativos. Además, es mejor no tomar inmediatamente un patrón específico, el primero que parecía necesario, sino observar varios patrones relacionados del mismo grupo que resuelven el mismo problema.

Al mismo tiempo, es importante comprender el significado y el propósito del patrón, para representar claramente su organización abstracta y sus posibles implementaciones concretas. Un patrón puede tener diferentes implementaciones y cuanto más a menudo encuentre estas implementaciones, mejor comprenderá el significado del patrón. Pero no deberías utilizar un patrón si no lo entiendes, incluso si a primera vista te ayuda a resolver el problema.

Y, en última instancia, debemos cumplir con el principio KISS (Keep It Simple, Stupid): mantener el código del programa lo más simple y claro posible. Después de todo, el objetivo de los patrones no es complicar el código del programa, sino simplificarlo.

Los patrones de diseño son pautas para resolver problemas recurrentes. Estas no son clases, paquetes o bibliotecas que pueda conectar a su aplicación y sentarse a esperar un milagro. Más bien, son técnicas sobre cómo resolver ciertos problemas en determinadas situaciones.

Patrones generativos- patrones de diseño que abstraen el proceso de creación de instancias. Permiten independizar el sistema de la forma en que se crean, componen y presentan los objetos. Una plantilla generadora de clases utiliza la herencia para modificar la clase heredada, y una plantilla creadora de objetos delega la creación de instancias a otro objeto.

Existen los siguientes patrones generativos:

Fábrica sencilla

En programación orientada a objetos (POO), fábrica es un objeto para crear otros objetos. Formalmente, una fábrica es una función o método que devuelve objetos de un prototipo o clase mutable a partir de alguna llamada a un método que se considera "nuevo".

Ejemplo de la vida: Imagina que necesitas construir una casa y necesitas puertas. Sería una tontería ponerse el uniforme de carpintero y empezar a hacer una puerta cada vez que las necesite. En cambio, lo haces en una fábrica.

En palabras simples: Una fábrica simple genera una instancia para el cliente sin exponer ninguna lógica.

Pasemos al código. Tenemos la interfaz Door y su implementación:

Interfaz Puerta (función pública getWidth(): float; función pública getHeight(): float; ) clase WoodenDoor implementa Door (protegido $ancho; protegido $alto; función pública __construct(flotador $ancho, flotante $alto) ( $this-> ancho = $ancho; $this->alto = $alto; ) función pública getWidth(): float ( devuelve $this->ancho; ) función pública getHeight(): float ( devuelve $this->alto; )

Luego tenemos nuestro DoorFactory que crea una puerta y la devuelve:

Clase DoorFactory (función estática pública makeDoor($ancho, $alto): Puerta (devuelve nueva WoodenDoor($ancho, $alto); ) )

Y luego podemos usar todo esto:

$puerta = DoorFactory::makeDoor(100, 200); eco "Ancho: ". $puerta->getWidth(); eco "Altura: ". $puerta->getHeight();

Cuando usar: Cuando crear un objeto no son solo unas pocas asignaciones, sino algún tipo de lógica, entonces tiene sentido crear una fábrica separada en lugar de repetir el mismo código en todas partes.

Método de fábrica

Método de fábrica- un patrón de diseño generativo que proporciona a las subclases una interfaz para crear instancias de una clase. En el momento de la creación, los herederos pueden determinar qué clase crear. En otras palabras, esta plantilla delega la creación de objetos a los descendientes de la clase padre. Esto le permite no utilizar clases específicas en el código del programa, sino manipular objetos abstractos en un nivel superior.

Ejemplo de la vida: Considere el ejemplo de un gerente de contratación. Es imposible que una sola persona entreviste a todos los candidatos para todos los puestos. Dependiendo de la vacante deberá distribuir las etapas de la entrevista entre diferentes personas.

En palabras simples: El administrador proporciona una manera de delegar la lógica de creación de instancias a clases secundarias.

Pasemos al código. Considere el ejemplo anterior sobre un gerente de recursos humanos. Inicialmente tenemos una interfaz de Interviewer y varias implementaciones para la misma:

Interfaz Entrevistador (función pública preguntarPreguntas(); ) clase Desarrollador implementa Entrevistador (función pública preguntarPreguntas() ( echo "¡Preguntar sobre patrones de diseño!"; ) ) clase CommunityExecutive implementa Entrevistador (función pública preguntarPreguntas() ( echo "Preguntar sobre cómo trabajar con el comunidad "; ) )

Ahora creemos nuestro HiringManager:

Clase abstracta HiringManager ( // Método de fábrica función pública abstracta makeInterviewer(): Entrevistador; función pública takeInterview() ( $entrevistador = $this->makeInterviewer(); $entrevistador->askQuestions(); ) )

Y ahora cualquier clase infantil puede ampliarlo y proporcionar el entrevistador necesario:

La clase DevelopmentManager extiende HiringManager (función pública makeInterviewer(): Entrevistador (devuelve nuevo Desarrollador(); )) la clase MarketingManager extiende HiringManager (función pública makeInterviewer(): Entrevistador (devuelve nuevo CommunityExecutive(); ) )

Ejemplo de uso:

$devManager = nuevo DevelopmentManager(); $devManager->takeInterview(); // Salida: ¡Preguntas sobre patrones de diseño! $marketingManager = nuevo MarketingManager(); $marketingManager->takeInterview(); // Salida: Pregunta sobre cómo trabajar con la comunidad

Cuando usar:Útil cuando hay algún procesamiento general en una clase, pero la subclase requerida se determina dinámicamente en tiempo de ejecución. Es decir, cuando el cliente no sabe qué subclase puede necesitar.

Fábrica abstracta

Fábrica abstracta- un patrón de diseño generativo que proporciona una interfaz para crear familias de objetos interrelacionados o interdependientes sin especificar sus clases específicas. El patrón se implementa mediante la creación de una clase abstracta Factory, que proporciona una interfaz para crear componentes del sistema (por ejemplo, para una interfaz de ventana, puede crear ventanas y botones). Luego se escriben clases que implementan esta interfaz.

Ejemplo de la vida: Ampliemos nuestro ejemplo sobre puertas de una fábrica sencilla. Dependiendo de tus necesidades, necesitarás una puerta de madera de una tienda, una puerta de hierro de otra o una puerta de plástico de una tercera. Además, necesitará un especialista adecuado: un carpintero para una puerta de madera, un soldador para una puerta de hierro, etc. Como puede ver, existe una dependencia entre las puertas.

En palabras simples: Fábrica de fábricas. Una fábrica que agrupa fábricas individuales pero relacionadas/dependientes sin especificar sus clases específicas.

Miremos el código. Usemos el ejemplo de las puertas. Primero tenemos la interfaz Door y varias de sus implementaciones:

Interfaz Puerta (función pública getDescription(); ) clase WoodenDoor implementa Puerta (función pública getDescription() ( echo "Soy una puerta de madera"; ) ) clase IronDoor implementa Puerta (función pública getDescription() ( echo "Soy una puerta de hierro "; ) )

Luego tenemos varios DoorFittingExperts para cada tipo de puerta:

Interfaz DoorFittingExpert ( función pública getDescription(); ) clase Welder implementa DoorFittingExpert ( función pública getDescription() ( echo "Solo trabajo con puertas de hierro"; ) ) clase Carpenter implementa DoorFittingExpert ( función pública getDescription() ( echo "Solo trabajo con puertas de madera"; ) )

Ahora tenemos un DoorFactory que nos permitirá crear una familia de objetos relacionados. Es decir, la fábrica de puertas de madera nos proporcionará una puerta de madera y un experto en puertas de madera. Lo mismo para puertas de hierro:

Interfaz DoorFactory ( función pública makeDoor(): Puerta; función pública makeFittingExpert(): DoorFittingExpert; ) // La fábrica de madera devolverá una puerta de madera y una clase de carpintero WoodenDoorFactory implementa DoorFactory ( función pública makeDoor(): Puerta ( return new WoodenDoor() ; ) public function makeFittingExpert(): DoorFittingExpert ( return new Carpenter(); ) ) // La fábrica de hierro devolverá una puerta de hierro y una clase de soldador IronDoorFactory implementa DoorFactory ( public function makeDoor(): Door ( return new IronDoor(); ) función pública makeFittingExpert(): DoorFittingExpert ( devuelve nuevo Welder(); ) )

Ejemplo de uso:

$fabricademadera = nuevaFábricaDePuertademadera(); $puerta = $fabricademadera->hacerPuerta(); $experto = $fabricademadera->makeFittingExpert(); $puerta->getDescription(); // Salida: Soy una puerta de madera $experto->getDescription(); // Salida: solo trabajo con puertas de madera // Lo mismo ocurre con una puerta de hierro $ironFactory = new IronDoorFactory(); $puerta = $ironFactory->makeDoor(); $experto = $ironFactory->makeFittingExpert(); $puerta->getDescription(); // Salida: Soy una puerta de hierro $experto->getDescription(); // Conclusión: solo trabajo con puertas de hierro

Como puede ver, una fábrica de puertas de madera encapsula a un carpintero y una puerta de madera, y una fábrica de puertas de hierro encapsula una puerta de hierro y un soldador. Esto nos permitió asegurarnos de contar con el experto que necesitábamos para cada puerta.

Cuando usar: Cuando existen dependencias interconectadas con una lógica de creación no muy simple.

Constructor

Constructor es un patrón de diseño generativo que proporciona una manera de crear un objeto compuesto. Diseñado para resolver el problema del antipatrón “Constructor Telescópico”.

Ejemplo de la vida: Imagina que fuiste a McDonalds y pediste un producto específico, por ejemplo, un Big Mac, y te lo prepararon sin hacerte preguntas. Este es un ejemplo de una fábrica simple. Pero hay casos en los que la lógica de la creación puede implicar más pasos. Por ejemplo, si quieres un sándwich personalizado en Subway: tienes varias opciones sobre cómo se preparará. ¿Qué tipo de pan quieres? ¿Qué salsas debo usar? ¿Qué queso? En tales casos, la plantilla "Constructor" viene al rescate.

En palabras simples: Una plantilla le permite crear diferentes vistas de un objeto sin saturar el constructor. Es útil cuando puede haber varias vistas de un objeto o cuando hay muchos pasos involucrados en su creación.

Déjame mostrarte con un ejemplo qué es un “Constructor Telescópico”. Érase una vez todos vimos un constructor como este:

Función pública __construct($tamaño, $queso = verdadero, $pepperoni = verdadero, $tomate = falso, $lechuga = verdadero) ( )

Como puede ver, la cantidad de parámetros del constructor puede aumentar dramáticamente, lo que dificulta comprender la ubicación de los parámetros. Además, esta lista de opciones seguirá creciendo si deseas agregar nuevas opciones. Este es el “Constructor Telescópico”.

Pasemos a un ejemplo en código. Una alternativa adecuada sería utilizar la plantilla "Constructor". Primero tenemos una hamburguesa que queremos crear:

Clase Hamburguesa (protegido $tamaño; protegido $queso = falso; protegido $pepperoni = falso; protegido $lechuga = falso; protegido $tomate = falso; función pública __construct(BurgerBuilder $constructor) ( $este->tamaño = $constructor-> tamaño; $this->queso = $builder->queso; $this->pepperoni = $builder->pepperoni; $this->lechuga = $builder->tomate;

Luego tomamos "Constructor":

Clase BurgerBuilder ( público $tamaño; público $queso = falso; público $pepperoni = falso; público $lechuga = falso; público $tomate = falso; función pública __construct(int $tamaño) ( $este->tamaño = $tamaño; ) función pública agregarPepperoni() ( $this->pepperoni = true; devolver $this; ) función pública addLettuce() ( $this->lechuga = true; devolver $this; ) función pública addCheese() ( $this->cheese = verdadero; devolver $esto; ) función pública agregarTomato() ( $esto->tomato = verdadero; devolver $esto; ) función pública construir(): Hamburguesa ( devolver nueva hamburguesa($esto); )

Ejemplo de uso:

$hamburguesa = (new BurgerBuilder(14)) ->addPepperoni() ->addLettuce() ->addTomato() ->build();

Cuando usar: Cuando puede haber varios tipos de un objeto y se debe evitar el “constructor telescópico”. La principal diferencia con "fábrica" ​​es que se usa cuando la creación requiere un paso, mientras que "constructor" se usa cuando hay muchos pasos.

Prototipo

Especifica los tipos de objetos que se crearán utilizando una instancia de prototipo y crea nuevos objetos copiando este prototipo. Le permite alejarse de la implementación y le permite seguir el principio de "programación a través de interfaces". El tipo de retorno es la interfaz/clase abstracta en la parte superior de la jerarquía, y las clases descendientes pueden sustituir allí a un descendiente que implemente este tipo.

Ejemplo de la vida:¿Recuerdas a Dolly? Una oveja que fue clonada. No profundicemos más, lo principal es que aquí todo gira en torno a la clonación.

En palabras simples: Un prototipo crea un objeto basado en un objeto existente mediante clonación.

Es decir, te permite crear una copia de un objeto existente y modernizarlo según tus necesidades, en lugar de crear el objeto desde cero.

Miremos el código. En PHP esto se puede implementar fácilmente usando clonar:

Clase Oveja ( $nombre protegido; $categoría protegida; función pública __construct(cadena $nombre, cadena $categoría = "Oveja de montaña") ( $this->nombre = $nombre; $this->categoría = $categoría; ) función pública setName(cadena $nombre) ( $this->nombre = $nombre; ) función pública getName() ( return $this->nombre; ) función pública setCategory(cadena $categoría) ( $this->categoría = $categoría; ) función pública getCategory() (retorna $this->category;))

Luego se puede clonar así:

$original = nueva Oveja("Jolly"); echo $original->getName(); // Alegre eco $original->getCategory(); // Oveja montesa // Clonando y modificando lo que necesitamos $cloned = clone $original; $clonado->setName("Dolly"); echo $clonado->getName(); // Dolly echo $clonado->getCategory(); // Oveja de montaña

También puedes utilizar el método mágico __clone para cambiar el comportamiento de clonación.

Cuando usar: Cuando se necesita un objeto similar a un objeto existente, o cuando su creación sería más costosa que la clonación.

Semifallo

solitario Es un patrón de diseño generativo que garantiza que solo haya una instancia de una clase en una aplicación de proceso único y proporciona un punto global de acceso a esa instancia.

Ejemplo de la vida: Un país sólo puede tener un presidente a la vez. El mismo presidente debe actuar cuando las circunstancias lo requieran. El presidente aquí es un solitario.

En palabras simples: Garantiza que el objeto que se está creando sea el único objeto de su clase.

En general, el patrón singleton se reconoce como un antipatrón; se debe evitar su uso excesivo. No es necesariamente malo y puede tener usos útiles, pero debe usarse con precaución porque introduce un estado global en su aplicación y cambiarlo en un lugar puede afectar otras partes de la aplicación, dificultando la depuración. La otra desventaja es que acopla el código.

Nota traducción Lea más sobre los peligros de la plantilla singleton en.

Pasemos al código. Para crear un singleton, haga que el constructor sea privado, deshabilite la clonación y la extensión y cree una variable estática para contener la instancia:

Presidente de clase final ( instancia privada estática $; función privada __construct() ( // Ocultar el constructor ) función estática pública getInstance(): Presidente ( if (!self::$instancia) ( self::$instancia = new self() ) return self::$instance; ) función privada __clone() ( // Deshabilitar la clonación ) función privada __wakeup() ( // Deshabilitar la deserialización ) )

Ejemplo de uso:

$president1 = Presidente::getInstance(); $president2 = Presidente::getInstance(); var_dump($presidente1 === $presidente2); // verdadero




Arriba