Patrones Diseño


Definición

En Ingeniería del Software, un patrón de diseño1 es una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características. Una de ellas es que debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. Otra es que debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.

Lista de patrones de diseño

Base de datos como Adapter

Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se pretendía usar pySqlite para gestionar las bases de datos, para lo cual se ha tenido que crear un adaptador que se adecue a las necesidades del programa.
Aplicabilidad: Este patrón se usa cuando:

  • Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
  • Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.

Así, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.

Estructura:

database-diagram

Participantes:
Target: Journal y History. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target.
Adaptee: PySqlite. Define una interfaz existente que necesita adaptarse.
Adapter: DatabaseWrapper. Adapta la interfaz de pySqlite a Journal y History.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Se ha creado una nueva clase que será el Adaptador (DatabaseWrapper), que extienda del componente existente (pySqlite) e implemente la interfaz obligatoria. De este modo, se tiene la funcionalidad que deseada y se cumple la condición de implementar la interfaz.

Del mismo modo se puede decir que Journal y History adaptan DatabaseWrapper para que un cliente, ya sea Watcher, Scheduler, o SnapshotManager, puedan hacer uso de él.

SnapshotManager como Abstract Factory

Nombre del patrón: Abstract Factory.
Clasificación del patrón: Creacional.
Intención: Crear diferentes familias de objetos.
Motivación: El patrón de diseño Abstract Factory aborda el problema de la creación de familias de objetos que comparten toda una serie de características comunes en los objetos que componen dichas familias.
Desde un principio, el equipo de desarrollo supo que se centraría en una factoría concreta, xDelta3, pero la intención de incluir nuevas familias, por ejemplo ZFS y LVM motivó a desarrollar este diseño para facilitar este futuro acoplamiento.
Aplicabilidad:

  • El uso de este patrón está recomendado para situaciones en las que se tiene una familia de productos concretos y se preveé la inclusión de distintas familias de productos en un futuro.
  • Un sistema debe ser independiente de cómo se crean, componen y representan sus productos.
  • Un sistema debe ser configurado con una familia de productos entre varias.
  • Una familia de objetos producto relacionados está diseñada para ser usada conjuntamente y es necesario hacer cumplir esa restricción.
  • Se quiere proporcionar una biblioteca de clases producto y sólo se quiere revelar sus interfaces y no sus implementaciones.

Participantes: La estructura del patrón Abstract Factory es la siguiente:
Client: SnapshotManager. Sólo conoce la clases abstracta, IstorageWrapper, de los componentes.
AbstractFactory: Define métodos abstractos para crear instancias de clases Producto concretas.(IStorageWrapper)
ConcreteFactory: Implementan los métodos definidos por la superclase AbstractFactory para crear instancias de clases Producto concretas.
Métodos de creación de los productos genéricos en la interfaz de la fábrica (makeSnapshot, recoverSnapshot, recoverBackups…) que retornan una versión en un momento dado.
Son cada uno de los distintos wrappers (xDelta3Wrapper, LVMWrapper, ZFSWrapper) para crear el objeto de la tecnología pertinente.
Colaboraciones: Normalmente, una instancia de la clase ConcreteFactory es creada en tiempo de ejecución. Esta fábrica crea objetos de Producto concretos teniendo en cuenta una implementación particular. Para crear objetos de Producto diferentes, los clientes deberían usar una fábrica concreta distinta.
Al instanciar SnapshotManager se elige por parámetro la factoría a utilizar.
La clase abstracta AbstractFactory (IstorageWrapper) difiere la creación de objetos Producto a su subclase ConcreteFactory (los distintos wrappers).
Consecuencias:

  • Aísla clases concretas: Este patrón ayuda a controlar los productos que una aplicación crea porque encapsula la responsabilidad y el proceso de creación de objetos y aísla a los clientes de las implementaciones.
  • Se puede cambiar de familia de productos : Para cambiar de productos se debe cambiar de fábrica concreta.
  • Promueve la consistencia entre productos: Cuando los productos son diseñados para trabajar en conjunto, es importante que en una aplicación se utilicen objetos de una familia a la vez.
  • Desventaja: es difícil dar cabida a nuevos tipos de productos. Para crear nuevos tipos de productos es necesario crear una nueva fábrica concreta e implementar todas las operaciones que ofrece la superclase AbstractFactory.

Como conclusión se puede decir que este patrón está aconsejado cuando se prevé la inclusión de nuevas familias de productos, pero puede resultar contraproducente cuando se añaden nuevos productos o cambian los existentes.
Usos conocidos: Creación de familias de interfaces gráficos en las cuales los elementos (productos) del interfaz se mantienen constantes (por ejemplo labels, botones, cajas de texto …) pero el dibujado de dichos elementos puede delegarse en distintas familias (por ejemplo QT, GTK, etc) de forma que, en función de la fábrica seleccionada obtenemos unos botones u otros.
Patrones relacionados: Cuando se usa en conjunción con Singleton se crea una única fábrica, de modo que no habrá usos inconsistentes de los productos en el programa.
En este caso se usará el patrón Monostate en lugar del Singleton.

SnapshotManager como Façade

Nombre del patrón: Façade.
Clasificación del patrón: Estructural.
Intención: El patrón de diseño façade sirve para proveer de una interfaz unificada sencilla que haga de intermediaria entre un cliente y una interfaz o grupo de interfaces más complejas.
Motivación:

  • Crear un intermediario y realizar llamadas a la biblioteca sólo o, sobre todo, a través de él.
  • Crear una API intermedia, bien diseñada, que permita acceder a la funcionalidad de las demás.
  • Un objetivo de diseño general es minimizar la comunicación y dependencias entre subsistemas. Un modo de lograrlo es introducir un objeto fachada que proporciona una interfaz unificada a la funcionalidad del subsistema.

Aplicabilidad: Úsese el patrón Façade cuando se desee:

  • Proporcionar una interfaz simple para un subsistema complejo, evitando así que la mayoría de clientes tengan que conocer todas las clases internas del subsistema.
  • Desacoplar un subsistema de sus clientes y otros subsistemas, promoviendo así la independencia entre subsistemas (y, por tanto, la portabilidad).

Participantes:
Façade: IstorageWrapper, sabe qué clases del subsistema son las responsables de llevar a cabo cada petición. Delega las peticiones de los clientes a los objetos apropiados del subsistema.
Clases del subsistema: Los distintos wrapper, que implementan la funcionalidad del subsistema.
Colaboraciones: IstorageWrapper es un interfaz que hace que los wrappers tengan una fachada común.
Consecuencias:

  • Reduce el número de objetos con el que tienen que tratar los clientes, haciendo que el subsistema sea más fácil de usar.
  • Promueve un bajo acoplamiento entre el subsistema y los clientes.
    • Permite variar sus componentes sin que los clientes se vean afectados.
    • Ayuda a estructurar en capas un sistema.

Implementación: Reducir el acoplamiento entre cliente y subsistema: Haciendo que el Façade sea una clase abstracta o una interfaz.
O configurándolo con diferentes objetos del subsistema.
Clases del subsistema públicas o privadas: Sería útil hacer que determinadas clases del subsistema fueran privadas, aunque pocos lenguajes lo permiten.
Patrones relacionados: Adapter.

SnapshotManager como Adapter

Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se quería usar xDelta3, ZFS y LVM para crear las versiones, para lo cual se ha tenido que crear un adaptador para cada una de ellas, de forma que cumplan la funcionalidad requerida.
Aplicabilidad: Este patrón se usa cuando:

  • Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
  • Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.

De esta forma, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.
Participantes:
Target: IStorageWrapper. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target. (SnapshotManager)
Adaptee: xDelta3, ZFS y LVM. Definen las interfaces existentes que necesitan adaptarse.
Adapter: xDelta3Wrapper, ZFSWrapper, LVMWrapper. Adaptan la interfaz de xDelta3, ZFS y LVM respectivamente.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo se tiene la funcionalidad deseada y se cumple la condición de implementar la interfaz.
Patrones relacionados: Façade.

SnapshotManager como Monostate

Nombre del patrón: Monostate.
Clasificación del patrón: Creacional.
Intención: Asegura que todas las instancias tengan un estado común.
Motivación: Se accede a las versiones desde distintos puntos, y el estado ha de ser el mismo para todas.
Aplicabilidad: Se utiliza cuando se debe tener el mismo estado independientemente del acceso.
Participantes:
Monostate: SnapshotManager.
Colaboraciones:
Consecuencias:
Implementación:
Patrones relacionados: Abstract Factory, Singleton.

Estructura del módulo SnapshotManager:

snapshotManager-diagram

ConfigFileManager como Singleton

Nombre del patrón: Singleton.
Clasificación del patrón: Creacional.
Intención: Garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella
Motivación: Se accede a la configuración del programa desde distintos puntos, y siempre hemos de referirnos a la misma instancia.
Aplicabilidad: Se utiliza cuando deba haber exactamente una instancia de una clase y deba ser accesible a los clientes desde un punto de acceso conocido.
Las situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.
Estructura: Código que implementa el patrón, controlando una única instancia:

    def __new__(self,watcher=None):
        # if the class has not been instanciated before do it
        # else return instance.
        if self.__instance is None:
            self.__configFilePath = os.getenv("HOME")+"/.hdlorean/config.cfg"
            self.__instance = object.__new__(self)
 
        if watcher is not None:
            self.__watcher = watcher
        return self.__instance

Participantes:
Singleton: ConfigFileManager, define un método instancia que permite que los clientes accedan a su única instancia. Instancia es un método de clase estático.
Colaboraciones: Los clientes acceden a una instancia de un Singleton exclusivamente a través de un método instancia de éste.
Consecuencias:
  • Acceso controlado a la única instancia.
  • Espacio de nombres reducido: no hay variables globales.
  • Puede adaptarse para permitir más de una instancia.

Implementación: El patrón Singleton se implementa creando en una clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
Patrones relacionados: Abstract Factory, Monostate.

Demonio hdloreand como Singleton

Nombre del patrón: Singleton.
Clasificación del patrón: Creacional.
Intención: Garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella
Motivación: Se accede a la configuración del programa desde distintos puntos, y siempre hemos de referirnos a la misma instancia.
Aplicabilidad: Se utiliza cuando deba haber exactamente una instancia de una clase y deba ser accesible a los clientes desde un punto de acceso conocido.
Las situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.
Estructura: Código que implementa el patrón, controlando una única instancia:

    def __new__(self):
        if self.__instance is None:
            self.__instance = object.__new__(self)
            db = Journal.Journal()
            db.createTable()
            self.__watcher = Watcher.Watcher()            
            self.__scheduler = Scheduler.Scheduler()
            bp = BackendProxy.BackendProxy(self.__watcher,self.__scheduler,self.__instance)
            self.__cfm = ConfigFileManager.ConfigFileManager()
        return self.__instance

Participantes:
Singleton: hdloreand es el demonio de la aplicación, define un método instancia que permite que los clientes accedan a su única instancia. Instancia es un método de clase estático.
Colaboraciones: Los clientes acceden a una instancia de un Singleton exclusivamente a través de un método instancia de éste.
Consecuencias:
  • Acceso controlado a la única instancia.
  • Espacio de nombres reducido: no hay variables globales.
  • Puede adaptarse para permitir más de una instancia.

Implementación: El patrón Singleton se implementa creando en una clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
Patrones relacionados: Abstract Factory, Monostate.

PyInotifyHandler como Adapter

Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: El equipo quería usar Inotify para gestionar los eventos que ocurren sobre un archivo vigilado. Se investigó su uso y se decidió utilizar el módulo pyInotify, incluído en python.
Aplicabilidad: Este patrón se usa cuando:

  • Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
  • Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.

Estructura:

pyinotifyhandler-diagram

Participantes:
Target: PyinotifyHandler. Define la interfaz específica del dominio que Client usa.
Client: Watcher. Colabora con la conformación de objetos para la interfaz Target.
Adaptee: PyInotify. Define una interfaz existente que necesita adaptarse.
Adapter: Pyinotifyhandler. Adapta la interfaz del pyInotify.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Python tiene el módulo pyInotify, el cual nos ofrece una manera genérica y abstracta para manipular las funcionalidades de inotify. Se ha creado una nueva clase, Pyinotifyhandler, que prepara las estructuras de datos y configura inotify para que la aplicación, (Watcher en particular) pueda gestionar los eventos de forma acorde al objetivo del programa.

El sistema de paso de mensajes DBUS como Mediator

Nombre del patrón: Mediator.
Clasificación del patrón: De comportamiento.
Intención: Definir un objeto que encapsule como interactúa un conjunto de objetos.
Motivación: Cuando muchos objetos interactúan con otros objetos, se puede formar una estructura muy compleja, con objetos con muchas conexiones con otros objetos. En un caso extremo cada objeto puede conocer a todos los demás objetos. Para evitar esto el patrón Mediator encapsula el comportamiento de todo un conjunto de objetos en un solo objeto.
Aplicabilidad: Usar el patrón Mediator cuando:

  • Un conjunto grande de objetos se comunica de una forma bien definida, pero compleja.
  • Reutilizar un objeto se hace difícil por que se relaciona con muchos objetos.
  • El comportamiento de muchos objetos que esta distribuido entre varias clases, puede resumirse en una o varias por subclasificación.

Participantes:
Mediator (BackendProxy y FrontendProxy): Implementa el comportamiento cooperativo entre los colegas (como se comunican entre ellos). Además los conoce y mantiene. Debido a las peculiaridades de DBUS, FrontendProxy recibe las peticiones de GUI y UI y se las transmite a BackendProxy, que es el encargado de enviarla al colega destinatario.
Colleagues: Cada colega conoce su mediador, y usa a este para comunicarse con otros colegas.
Colaboraciones: Los colegas envían y reciben requerimientos (requests) de un objeto mediador. El mediador implementa como se comunican los colegas.
Consecuencias: El patrón Mediator tiene los siguientes beneficios y desventajas:

  • Desacopla a los colegas: el patrón Mediator promueve bajar el acoplamiento entre colegas. Se puede variar y reutilizar colegas y mediadores independientemente .
  • Simplifica la comunicación entre objetos: Los objetos que se comunican de la forma "muchos a muchos" puede ser remplazada por una forma "uno a muchos" que es menos compleja y más elegante. Además esta forma de comunicación es más fácil de entender.
  • Abstrae como los objetos cooperan: Haciendo a la mediación un concepto independiente y encapsulándolo en un objeto permite enfocar como los objetos interactúan. Esto ayuda a clarificar como los objetos se relacionan en un sistema.
  • Centraliza el control: El mediador es el que se encarga de comunicar a los colegas, este puede ser muy complejo, difícil de entender y modificar.

Implementación:
Omitir la clase abstracta Mediator. No es necesario crear una clase abstracta Mediador cuando los objetos solo trabajan con un mediador. El acoplamiento abstracto de dicha clase permite que los objetos trabajen con diferentes subclases Mediator y viceversa.
Comunicación Objeto y Mediador. Los objetos se comunican su mediador cuanto tiene lugar un evento. Las clases de objetos cada vez que cambian su estado envían notificaciones al mediador. El mediador responde propagando los efectos de dichos eventos a los otros objetos.
Otra forma define al Mediador una interfaz de notificación especializada que permite a los objetos ser mas directos en su comunicación.
Usos conocidos: La arquitectura de Smalltalk/V para Windows usan objetos parecidos a mediadores entre los útiles de los diálogos.
Patrones relacionados: Un patrón muy parecido a éste es el Façade que se diferencia en que abstrae un sistema de objetos proporcionado una interfaz mas conveniente, utilizando un protocolo unidireccional (Fachada realiza solo peticiones a las clases del subsistema pero no a la inversa), mientras que el Mediator usa un protocolo mutidireccional.
Con el patrón Observer los objetos pueden comunicarse con el mediador.

El sistema de paso de mensajes DBUS como Observer

Nombre del patrón: Observer.
Clasificación del patrón: De comportamiento.
Intención: Definir una dependencia entre un objeto y un conjunto de ellos, de modo que los cambios en el primero se vean reflejados en los otros.
También conocido como: Spider.
Motivación: Frontend ha de recibir señales desde el backend que nos informen de que ha habido un cambio en algún archivo vigilado y así refrescar el treeview de GUI, por ejemplo.
Aplicabilidad: Se usa en casos en que se desea desacoplar la clase de los objetos clientes del objeto, aumentando la modularidad del lenguaje, así como evitar bucles de actualización (espera activa o polling).
Participantes:
Sujeto: Mantiene una lista de observadores y proporciona una interfaz para su gestión.
Observador: Define una interfaz para actualizar los objetos que deben reflejar los cambios en el sujeto.
Observador concreto: Mantiene una referencia a una sujeto concreto, almacenando parte de su estado e implementado la interfaz de Observador.
Colaboraciones: El Sujeto notifica a sus observadores de los cambios que sufre. Los observadores concretos solicitan a su sujeto los datos necesarios para mantener la consistencia con su nuevo estado.
Consecuencias:

  • Permite reutilizar sujetos y observadores por separado.
  • Permite añadir nuevos observadores sin modificar al sujeto o a otros observadores.
  • Que el sujeto no informe a sus observadores de qué cambio ha sufrido permite mantener el acoplamiento en un nivel bajo, puesto que el observador sólo pide los datos del estado del sujeto que le interesan.
  • Aunque el observador no esté interesado en ciertos cambios del sujeto será notificado de ellos.
  • Se pueden realizar implementaciones con observadores que coordinan información sobre varios sujetos.
  • Los cambios en el sujeto pueden ser solicitados por objetos que no son observadores.

Implementación: El backend generará una señal que recibirá el frontend, que previamente se había suscrito a ella.
Usos conocidos: Este patrón suele observarse en los marcos de interfaces gráficas orientados a objetos, en los que la forma de capturar los eventos es suscribir 'listeners' a los objetos que pueden disparar eventos.

El sistema de paso de mensajes DBUS usando Proxys

Nombre del patrón: Proxy.
Clasificación del patrón: Estructural.
Intención: Proporciona un representante o sustituto de otro objeto para controlar el acceso a éste.
Motivación: La interfaz gráfica y la consola necesitan interaccionar con el demonio de la aplicación. Para ello se crea un sustituto de los distintos objetos a los que se ha de acceder.
Aplicabilidad:

  • Un proxy remoto proporciona un representante local de un objeto remoto.
  • Un proxy virtual crea objetos costosos sólo cuando es necesario.
  • Un proxy de protección controla el acceso al objeto original.
  • Una referencia inteligente es un sustituto de un simple puntero que realiza alguna acción adicional:
    • Contar el número de referencias al objeto original.
    • Cargar un objeto persistente en memoria cuando es referenciado por vez primera.
    • Bloquea el acceso al objeto real para que no sea modificado por otro objeto.

Participantes:
Client: Elemento que desea acceder al objeto.
Proxy: Mantiene una referencia para acceder al objeto original.
* Proporciona una interfaz idéntica a la del Subject.
* Controla el acceso al objeto y puede encargarse de crearlo, borrarlo…
BackendProxy proporciona un representante de distintos objetos reales.
Subject: Define el objeto real representado por el Proxy. Watcher, Scheduler, SnapshotManager.
Colaboraciones: Client accede a Subject a través de Proxy.
Patrones relacionados: Singleton.

BackendProxy y FrontendProxy como Singleton

Las clases BackendProxy y FrontendProxy están implementadas con el patrón Singleton para que se use siempre la misma instancia.

Estructura del sistema de paso de mensajes entre backend y frontend:

dbus-diagram

HDLogger como Adapter

Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se quería hacer un módulo de logger para centralizar la recogida de información relevante para la depuración de problemas. Para ello se ha decidido adaptar el módulo de logger de python.
Aplicabilidad: Este patrón se usa cuando:

  • Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
  • Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.

De esta forma, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.
Estructura:

hdlogger-diagram

Participantes:
Target: HDLogger. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target. Son todas aquellas clases que hacen uso del logger.
Adaptee: librería logging de Python. Define la librería que ha de adaptarse.
Adapter: HDLogger. Adaptan el logger de python.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo se tiene la funcionalidad deseada y se cumple la condición de implementar la interfaz.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License