toniGitH /
Patron-Prototype
Explicación del patrón Prototype y ejemplo de uso en PHP
Loading repository data…
toniGitH / repository
Explicación del patrón Adapter y ejemplo de uso en PHP
Repositorio creado para explicar el patrón Adapter y su implementación mediante un ejemplo práctico en PHP (Aplicación de inventario).
El patrón Adapter es un patrón estructural que permite que una aplicación utilice un servicio con una interfaz incompatible, introduciendo una capa intermedia o adaptador que traduce la forma de uso del servicio a la interfaz que la aplicación espera.
Este patrón propone la creación de una Interface Target que define la forma de uso del servicio que la aplicación espera, y que es implementada por la clase Adapter, quien "envuelve" al servicio incompatible y lo adapta a la interfaz que la aplicación espera.
Para que una aplicación funcione, ésta necesita interactuar con diferentes servicios, los cuales, si son externos, pueden tener interfaces incompatibles con las que espera la aplicación.
Aquí, por interfaz no entendemos una Interface propiamente dicha, sino algo más general, una manera concreta de interactuar con un determinado servicio.
Como normalmente la aplicación no puede acceder al código de ese servicio externo para adaptarlo a sus necesidades, lo que propone este patrón es crear una estructura intermedia que, sin cambiar ni la aplicación ni el servicio externo, permita que ambos puedan interactuar entre sí.
Dicha estructura intermedia, según la definición más pura de este patrón consiste en la creación de dos elementos que haran de "puente" entre la aplicación y el servicio incompatible: una Interface Target y una clase Adapter.
1️⃣ Interface Target: define la forma de uso del servicio que la aplicación espera y conoce (se crea dentro de la propia aplicación y forma parte de ella).
Como es una Interface, sólo declara el método o métodos a los que la aplicación va a "apuntar" (de ahí lo de Target u objetivo) para obtener lo que necesita del servicio. Por tanto, la aplicación no conoce al servicio incompatible, sólo conoce a la Interface Target.
2️⃣ Clase Adapter: implementa la Interface Target y "envuelve" o usa el servicio incompatible, adaptándolo a esa interfaz que la aplicación espera.
Este adaptador también se crea dentro de la propia aplicación y forma parte de ella.
Dentro de dicho adaptador:
Interface Target, que quedan a "disposición" de la aplicación, y que internamente están llamando al servicio incompatible, haciendo de "traductor" o "intermediario" entre la aplicación y el servicio incompatible.1️⃣ Cliente o Aplicación que necesita el servicio: es la aplicación en sí, que necesita obtener algo de un servicio externo. Ya existe y no se pretende modificar.
2️⃣ Servicio externo incompatible: es el servicio externo que la aplicación necesita, pero que tiene una interfaz o forma de acceder incompatible con la que espera la aplicación. Suele ser algo que ya existe previamente y normalmente no se puede modificar porque a menudo suele ser un servicio de terceros.
3️⃣ Interface Target: define la forma en la que la aplicación espera utilizar el servicio. Esta interface se crea dentro de la propia aplicación y forma parte de ella. Se debe crear expresamente, según indica el patrón, o al menos, debe existir previamente (como el caso del ejemplo de este repositorio).
4️⃣ Adaptador: es la clase que hace de estructura intermedia que permite que la aplicación y el servicio incompatible puedan interactuar entre sí. Implementa la Interface Target y envuelve o usa el servicio incompatible. Es una clase que se crea expresamente, según indica el patrón.
Utiliza la clase adaptadora cuando quieras usar una clase existente, pero cuya interfaz no sea compatible con el resto del código.
El patrón Adapter te permite crear una clase intermedia que sirva como traductora entre tu código y una clase heredada, una clase de un tercero o cualquier otra clase con una interfaz extraña.
Utiliza el patrón cuando quieras reutilizar varias subclases existentes que carezcan de alguna funcionalidad común que no pueda añadirse a la superclase.
Aplicando este patrón, puedes colocar la funcionalidad que falta dentro de una clase adaptadora. Después puedes envolver objetos a los que les falten funciones, dentro de la clase adaptadora, obteniendo esas funciones necesarias de un modo dinámico. Para que esto funcione, las clases en cuestión deben tener una interfaz común y el campo de la clase adaptadora debe seguir dicha interfaz.
Aplicando este patrón se están siguiendo los principios de solid:
getProductList() de formas diferentes.Imagina que tenemos una aplicación de inventario que, a partir de la obtención de una lista de productos, genera algún tipo de reporte o resultado, eliminando los productos que no tienen stock, listándolos con sus cantidades y costes, y obteniendo el valor total de las existencias.
En nuestro ejemplo, esto es lo que hace la clase InventoryApp.
Esta clase obtiene el listado de los productos de un servicio interno, representado en la clase InternalProductService, y que, para una mejor comprensión del ejemplo, está implementando una Interface que ya tenemos creada en el proyecto, llamada ProductListProvider (esa es la Interface Target que venimos diciendo que la aplicación espera y conoce).
Sin embargo, nuestra aplicación podría querer trabajar con otros servicios que le proporcionen listas de productos, pero éstos podrían tener formas de obtener los productos diferentes o incompatibles con la que espera la aplicación.
Es el caso de los servicios externos A y B, representados en las clases ExternalServiceA y ExternalServiceB. El primero de ellos devuelve los datos en el formato que espera la aplicación (un array de objetos), mientras que el segundo devuelve los datos en un formato incompatible con la que espera la aplicación (un array de arrays).
Pero ambos servicios "trabajan" de forma diferente a como nuestra aplicación espera, por lo que no podemos usarlos directamente.
Para poder usarlos, el patrón Adapter nos propone crear una estructura intermedia, consistente en crear una Interface Target que entienda la aplicación, y una o varias clases Adapter, que sirvan de "intermediarias" entre la aplicación y los servicios externos.
Como la Interface Target ya la teníamos creada de inicio en nuestra aplicación, no hay que crear ninguna más. Esa es la Interface que nos servirá de referencia para crear los diferentes adaptadores.
Sólo nos queda crear los adaptadores necesarios, concretamente uno para el servicio externo A y otro para el servicio externo B, puesto que son diferentes entre sí y no nos sirve un mismo adaptador para ambos. Estos adaptadores también se crean dentro de la aplicación, y en nuestro ejemplo son las clases AdapterExternalServiceA y AdapterExternalServiceB.
Cada uno de dichos adaptadores recibirá, por inyección de dependencias, una instancia del servicio incompatible correspondiente para poder usarlo en su interior, y a su vez, implementará a su manera la Interface Target para comunicar a la aplicación con el servicio correspondiente.
En el flujo de la aplicación que se muestra en el archivo main.php podemos ver cómo se crea una instancia de la clase InventoryApp y esta es capaz de trabajar indistintamente con el servicio interno o con cualquiera de los servicios externos, gracias a los adaptadores.
En el caso del servicio interno, le pasamos la instancia de la clase InternalProductService al método getInventoryReport() de la clase InventoryApp.
En el caso de los servicios externos, le pasamos la instancia del adaptador correspondiente a la aplicación, por ejemplo, en el caso del servicio externo A, le pasamos la instancia de la clase AdapterExternalServiceA al método getInventoryReport() de la clase InventoryApp.
🚨 DETALLE IMPORTANTE
Dentro de nuestra aplicación, en la clase
InventoryApp, el métodogetInventoryReport(), que es el "corazón" de la aplicación y que realiza todo el trabajo una vez que dispone de la lista de productos, espera como parámetro una instancia de la claseProductListProvider, es decir, de laInterface Target, o mejor dicho, espera una instancia de cualquier clase que la implemente, ya sea de la claseInternalProductServiceo de cualquiera de los adaptadores que se creen para los servicios externos (AdapterExternalServiceAoAdapterExternalServiceB).
InventoryApp: la que contiene el "corazón" de la aplicación y que realiza todo el trabajo una vez que dispone de la lista de productos.ProductListProvider: nuestra Interface Target, la que conoce y espera nuestra aplicación y la que deben implementar los adaptadoresInternalProductService: que representa un servicio interno e implementa la Interface Target ProductListProvider.Product: define la estructura de los productos qSelected from shared topics, language and repository description—not editorial ratings.
toniGitH /
Explicación del patrón Prototype y ejemplo de uso en PHP
toniGitH /
Explicación del patrón Singleton y ejemplo de uso en PHP
toniGitH /
Explicación del patrón Builder y ejemplo de uso en PHP
toniGitH /
Explicación del patrón Facade y ejemplo de uso en PHP
toniGitH /
Explicación del patrón Decorator y ejemplo de uso en PHP
toniGitH /
Explicación del patrón Abstract Factory y ejemplo de uso en PHP