La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Javier Juárez González José Carlos Bernárdez Fdez. Alberto Barbosa León.

Presentaciones similares


Presentación del tema: "Javier Juárez González José Carlos Bernárdez Fdez. Alberto Barbosa León."— Transcripción de la presentación:

1 Javier Juárez González José Carlos Bernárdez Fdez. Alberto Barbosa León

2 INTENCIÓN Desacoplar una abstracción de su implementación, de manera que ambas puedan ser modificadas independientemente sin necesidad de alterar por ello la otra.

3 INTENCIÓN Es decir, se desacopla una abstracción de su implementación para que puedan variar independientemente.

4 MOTIVACIÓN Cuando una abstracción se puede implementar de varias maneras, lo normal para adaptarlas es usar herencia. Una clase abstracta define la interfaz a la abstracción y son las subclases las que las implementan de diferentes maneras.

5 MOTIVACIÓN Pero usar la herencia a veces no es suficientemente flexible, ya que une la abstracción y la implementación de forma permanente y esto hace dificil la modificación, extensión y reutilización de ambas de forma independiente.

6 EJEMPLO

7 MOTIVACIÓN Si queremos añadir una clase que pinte en ambas ventanas tenemos que crear una por cada tipo de ventana. Solo la implementación de la ventana debería depender de la plataforma en la que la aplicación corre. Necesitamos proporcionar una interfaz estable, uniforme y cerrada al no permitir cambios directos del código, pero abierta al permitir la ampliación. El patrón Bridge soluciona este problema poniendo la abstracción y su implementación en jerarquías de clases separadas.

8

9 APLICABILIDAD Se usa el patrón Bridge cuando: Se desea evitar un enlace permanente entre la abstracción y su implementación. Esto puede ser debido a que la implementación debe ser seleccionada o cambiada en tiempo de ejecución. Tanto las abstracciones y sus implementaciones deben ser extensibles por medio de subclases. En este caso, el patrón Bridge permite combinar abstracciones e implementciones diferentes y extenderlas independientemente. Cambios en la implementación de una abstracción no deben impactar en los clientes, es decir, su código no debe tener que ser recompilado.

10 APLICABILIDAD (En C++) Se desea esconder la implementación de una abstracción completamente a los clientes. La representación de una clase es visible en la interfaz de la clase. Se desea compartir una implementación entre múltiples objetos (quizá usando contadores), y este hecho debe ser escondido a los clientes.

11 ESTRUCTURA

12 PARTICIPANTES Abstraction define una interface abstracta. Mantiene una referencia a un objeto de tipo Implementor. RefinedAbstraction extiende la interface definida por Abstraction. Implementor define la interface para la implementación de clases. Esta interface no se tiene que corresponder exactamente con la interface de Abstraction. Típicamente la interface Implementor provee sólo operaciones primitivas, y Abstraction define operaciones de alto nivel basadas en estas primitivas. ConcreteImplementor implementa la interface de Implementor y define su implementación concreta.

13 COLABORACIONES Abstraction emite los pedidos de los clientes a su objeto Implementor.

14 CONSECUENCIAS 1.Desacopla interfaz e implementación: una implementación no es vinculada permanentemente a una interfaz. La implementación de una abstracción puede ser configurada en tiempo de ejecución. Además le es posible a un objeto cambiar su implementación en tiempo de ejecución. Desacoplando Abstraction e Implementor también elimina las dependencias sobre la implementación en tiempo de compilación. Cambiar una clase de implementación no requiere recompilar la clase Abstraction ni sus clientes. Esta propiedad es esencial cuando te debes asegurar la compatibilidad binaria entre diferentes versiones de una biblioteca de clases. Es más, este desacoplamiento fomenta las capas, que pueden conducir a un sistema mejor estructurado. La parte de alto nivel de un sistema sólo tiene que conocer Abstraction e Implementor. 2.Mejora la extensibilidad: se puede extender las jerarquías de Abstraction e Implementor independientemente. 3.Esconde los detalles de la implementación a los clientes.

15 IMPLEMENTACIÓN Sólo un Implementor. En situaciones donde existe sólo una implementación, crear una clase Implementor abstracta no es necesario. Esto es un caso especial del patrón; hay una relación uno-a- uno entre Abstraction e Implementor. Sin embargo, esta separación es útil cuando un cambio en la implementación de una clase no debe afectar a sus clientes, es decir, ellos no deben ser recompilados, sólo reenlazados. En C++, la interfaz de la clase Implementor puede ser definida en un archivo header privado el cual no es proveído a los clientes. Esto permite esconder una implementación de una clase completamente de sus clientes.

16 IMPLEMENTACIÓN Creando el objeto Implementor adecuado. ¿Cómo, cuándo y dónde que clase Implementor instanciar cuando hay más de una? Si Abstraction conoce todas las clases ConcreteImplementor puede instanciar una de ellas en su constructor; puede decidir cuál instanciar dependiendo de los parámetros del constructor. Otra aproximación es elegir una implementación inicial por defecto y cambiarla después acorde al uso. También es posible delegar la decisión a otro objeto en conjunto.

17 IMPLEMENTACIÓN Compartiendo implementadores: el estilo Handle/Body en C++ puede ser usado para compartir implementaciones de muchos objetos. Body almacena una cuenta de referencia que la clase Handle incrementa y decrementa. Usando herencia múltiple. Se puede usar herencia múltiple en C++ para asociar una interfaz con su implementación.

18 CÓDIGO DE EJEMPLO Sigamos con el ejemplo anterior y su implementación en C++ a partir del patrón Bridge. El problema tiene que ver con la implementación de una abstracción portable llamada Window para una interfaz de usuario. Esta abstracción nos deberá servir para aplicaciones que trabajan con dos plataformas, X Window y PM de IBM, por ejemplo. Usando herencia, tendremos una clase abstracta Window y dos subclases que implementen ésta para cada plataforma

19 CÓDIGO DE EJEMPLO Pero esto se puede volver alarmantemente peligroso en algunos casos. Por ejemplo, si queremos crear una subclase IconWindow de Window que dibuje iconitos, para que sea soportada por ambas plataformas deberemos implementar dos nuevas clases, XIconWindow y PMIconWindow. Esto se repetirá cada vez que añadamos un tipo de ventana.

20 CÓDIGO DE EJEMPLO Tenemos un terrible problema, el código cliente es ahora dependiente de la plataforma, error si se necesita código portable. El cliente debería ser capaz de crear una ventana sin decidir una implementación concreta. Sólo la implementación de ventana debería depender de la plataforma en la que corre la aplicación. Entonces el código cliente debería instanciar una ventana sin mencionar una plataforma específica. Usando el patrón Bridge solucionamos el problema poniendo la abstracción Window y su implementación en jerarquías de clases separadas.

21 CÓDIGO DE EJEMPLO Hay una jerarquía de clases para las interfaces ventana y una jerarquía separada para las implementaciones de ventana dependiendo de la plataforma

22 CÓDIGO DE EJEMPLO Vemos ahora el código en C++ que implementa el ejemplo. La clase Window define la abstracción ventana para las oplicaciones cliente: class Window{ Public: Window(View* contents); virtual void DrawContents() virtual void Open(); virtual void Close(); … virtual void SetOrigin(const Point& at); virtual void SetExtent(const Point& extent); … virtual void DrawLine(const Point&, const Point&); … protected: WindowImp* GetWindowImp(); View* GetView(); private: WindowImp* _imp; View* _contents; };

23 CÓDIGO DE EJEMPLO class WindowImp{ public: virtual void ImpTop(); virtual void ImpBottom(); … virtual void DeviceRect(Coord, Coord, Coord, Coord) = 0; virtual void DeviceText(cons char*, Coord, Coord) =0; … protected: WindowImp(); }; Subclases de Window definen distintos tipos de ventana que la aplicación podrá usar, veamos por ejemplo la clase AplicationWindow

24 CÓDIGO DE EJEMPLO Class ApplicationWindow : public Window{ Public: virtual void DrawContents(); }; void ApplicationWindow :: DrawContents(){ GetView()->DrawOn(this); } Subclases concretas de WindowImp soportan diferentes sistemas de ventanas. La subclase XWindowImp soporta el sistema X Window System, al igual que PMWindowImp soporta Presentation Manager (PM). Un ejemplo:

25 CÓDIGO DE EJEMPLO class XWindowImp : public WindowImp{ public: XWindowImp(); virtual void DeviceRect(Coord, Coord, Coord, Coord); … private: Display* _dpy; Drawable _winid; GC _gc; }; Estas subclases implementan las operaciones de WindowImp en términos de primitivas de un sistema de ventanas. Por ejemplo, DeviceRect es implementado para X como sigue:

26 CÓDIGO DE EJEMPLO void XWindowImp :: DeviceRect{ Coord x0, Coord y0, Coord x1, Coord y1) { int x = round(min(x0,x1)); int y = round(min(y0,y1)); int w = round(abs(x0 – x1)); int h = round(abs(y0 – y1)); XDrawRectangle(_dpy, _winid, _gc, x, y, w, h); } Y la pregunta buena es ¿Cómo una ventana obtiene una instancia de la subclase correcta de WindowImp? Asumiremos que Window tiene esa responsabilidad en este ejemplo. Una operación GetWindowImp devolverá la correcta instancia de un Abstract Factory que eficientemente encapsula todos los sistemas de ventanas específicos.

27 USOS CONOCIDOS Ademas del uso visto en JDBC de Java ademas podemos encontrar ejemplos en NeXT’s appkid que usa el patron Bridge en la implementacion y muestra de imágenes gráficas. También es utilizado en la librería libg++.

28 PATRONES RELACIONADOS Una Abstract Factory puede crear y configurar un Bridge particular.


Descargar ppt "Javier Juárez González José Carlos Bernárdez Fdez. Alberto Barbosa León."

Presentaciones similares


Anuncios Google