- Clasificación del patrón: estructural.
- Intención: transformar la interfaz de un objeto existente en otra que los clientes puedan utilizar. De este modo, una clase que no puede utilizar la primera, puede hacer uso de ella a través de la segunda.
- También conocido como: Wrapper.
- Aplicabilidad: Se utiliza este patrón cuando se necesita
- utilizar una clase existente, pero su interfaz no coincide con la que se necesita.
- crear una clase reutilizable que coopera con clases que no tienen interfaces compatibles.
- utilizar varias subclases existentes, pero como es poco práctico adaptar cada interfaz, se crea un objeto que adapte la interfaz de la clase padre.
Object Adapter: utiliza composición
Class Adapter: utiliza herencia múltiple
- Participantes:
- Target: define la interfaz específica que el cliente utiliza.
- Client: interactúa con los objetos según la interfaz de Target.
- Adaptee: define una interfaz existente que necesita ser adaptada.
- Adapter: adapta la interfaz de Adaptee a la interfaz de destino.
- Colaboraciones:
- Client-Adapter: el cliente llama a las operaciones de una instancia de Adapter.
- Adapter-Adaptee: el adaptador llama a las operaciones de Adaptee, quienes realizan la petición.
- Implementación:
- Crear una clase Adapter que hereda públicamente de Target y tiene una instancia de Adaptee o hereda en forma privada de este.
- Pluggable Adapters:
- encontrar una interfaz general para Adaptee (Adapter), que tenga un pequeño conjunto de operaciones que permitan hacer la adaptación.
- alguna de estas opciones:
- Uso de operaciones abstractas: se definen operaciones abstractas en el cliente y el Adapter debe implementarlas y adaptar el objeto Adaptee.
- Uso de objetos delegados mediante Strategy: el cliente puede utilizar un Strategy para asignarse un tipo de AdapterStrategy.
- Adaptadores parametrizados: el adaptador almacena un bloque para cada solicitud individual. No soporta adaptación de subclases.
- Consecuencias:
- Una clase adaptador:
- Al tratarse de herencia múltiple sólo puede
heredar de un adaptee concreto y no funcionará cuando queremos adaptar
una clase y sus subclases.
- No tiene que implementar un Adaptee por completo. Sólo aquellas partes
que necesita. También puede reemplazar el comportamiento del adaptee.
- al heredar del Adaptee no es necesario un puntero para acceder al Adaptee.
- Un objeto adaptador:
- puede tener uno o muchos Adaptees (el adaptee y
sus subclases, si posee). También puede agregar funcionalidad a todos
los Adaptees a la vez.
- Es más flexible, ya que escribe poco código y delega al Adaptee.
- Como se trata de manera general el
comportamiento de todos los Adaptee, si una subclase agrega nuevas
funcionalidades no se puede adaptar directamente. En ese caso se podría
tener un adaptador por cada tipo de subclase.
- Motivación: a veces, una clase no se puede reutilizar sólo porque su interfaz no coincide con la interfaz que una aplicación requiere.
- Ejemplos:
Dibujando un TextView en lugar de una figura
- Consecuencias:
- Una clase adaptador:
- Al tratarse de herencia múltiple sólo puede
heredar de un adaptee concreto y no funcionará cuando queremos adaptar
una clase y sus subclases.
- No tiene que implementar un Adaptee por completo. Sólo aquellas partes
que necesita. También puede reemplazar el comportamiento del adaptee.
- al heredar del Adaptee no es necesario un puntero para acceder al Adaptee.
- Un objeto adaptador:
- puede tener uno o muchos Adaptees (el adaptee y
sus subclases, si posee). También puede agregar funcionalidad a todos
los Adaptees a la vez.
- Es más flexible, ya que escribe poco código y delega al Adaptee.
- Como se trata de manera general el
comportamiento de todos los Adaptee, si una subclase agrega nuevas
funcionalidades no se puede adaptar directamente. En ese caso se podría
tener un adaptador por cada tipo de subclase.
Haciendo pasar pavo por pato
- Preguntas
- ¿Cuánto se debe adaptar? La cantidad de métodos a adaptar es proporcional a la interface que se debe soportar como Target.
- ¿El adaptador solo wrappea una clase? No, puede haber casos en que wrapee más de un Adaptee.
- Mi sistema debe trabajar con dos interfaces: una nueva y una vieja ¿Qué se puede hacer?. Crear un Two Way Adapter que implemente ambas interfaces implicados, por lo que el adaptador puede actuar como una interfaz vieja o nueva. Se puede utilizar herencia múltiple, porque las dos interfaces son substancialmete diferentes.
- Patrones relacionados:
- Bridge: separa una interfaz de su aplicación, de manera que pueda variar fácilmente y de forma independiente.
- Decorator: no altera la interfaz, pero agrega responsabilidad.
- Proxy: define un representante o sustituto de otro objeto sin cambiar su interfaz.
- Facade: hace que una interfaz sea más simple.