T ó p i c o s A v a n ç a d o s e m L i n g u a g e m d e P r o g r a m a ç ã o Padrões de Projeto Classificação: Propósito: Estrutural Escopo: Objetos Bridge Prof. Alexandre Vidal DEINF-UFMA Intenção: desacopla uma abstração de sua implementação de modo que elas possam variar independentemente. a.k.a.: handle/body Motivação: Motivação: o uso de herança para permitir diversas implementações de uma abstração pode não ser suficientemente flexível; interface e implementação ficam definitivamente ligadas e não podem ser usadas de modo independente; modificar a abstração afeta em geral as implementações. por exemplo: um código cliente deve ser capaz de criar um código de uma janela, sem se comprometer com um tipo específico de janela (e.g., Xwindow, IBM Presentation Manager, etc.); o padrão Bridge cria uma hierarquia para as interfaces de janela e uma hierarquia para cada implementação de janela específica de uma plataforma. A segunda hierarquia deriva de uma classe raiz WindowImp.
Motivação Aplicabilidade (quando usar o padrão): para evitar um conexão permanente entre abstração e implementação; para estender abstrações e suas implementações através de subclasses de modo independente; para evitar que mudanças na implementação atinjam os clientes; para evitar proliferação de classes (muitas classes de diferentes artefatos para diferentes ambientes em uma única hierarquia). Estrutura Participantes Abstraction: define a interface da abstração; mantém uma referência para o objeto Implementor; RefinedAbstraction: estende a interface definida pela abstração;
Participantes Implementor: define a interface para as classes de implementação; não precisa ser igual e normalmente é diferente da interface da abstração; Colaborações abstrações encaminham requisições dos clientes aos objetos implementadores. a interface da implementação define apenas operações primitivas, enquanto a interface da abstração define operações de alto nível baseadas nas operações primitivas. ConcreteImplementor: implementa a interface Implementor. Conseqüências Implementação (aspectos) separa interface de implementação; melhora as hierarquias de abstração e implementação(evolução independente); esconde detalhes de implementação dos clientes. apenas um Implementor: é um caso degenrado do Bridge; não precisa criar uma classe Implementor abstrata; ainda assim é útil por separar interface da implementação;
Implementação (aspectos) quando, como e onde decidir qual classe Implementor deve ser instanciada? no construtor da abstração, se ela conhece todas as implementações; possivelmente com base em parâmetros passados ao construtor; usar uma implementação default cambiável com o uso; usar uma AbstractFactory. Subclasses de Window definem os diferentes tipos de janelas que a aplicação poderia usar, tais como janelas de aplicação, ícones, janelas transientes para diálogos, paletas flutuantes, etc. class ApplicationWindow : public Window { public: //... virtual void DrawContents(); }; void ApplicationWindow::DrawContents () { GetView()->DrawOn(this); }
operações Window são definidas em termos da interface WindowImp. Por exemplo, DrawRect extrai quatro coordenadas de seus parâmetros Point antes de chamar a operação WindowImp que desenha o retângulo na jnela: void Window::DrawRect (const Point& p1, const Point& p2) { WindowImp* imp = GetWindowImp(); imp->devicerect(p1.x(), p1.y(), p2.x(), p2.y()); } subclasses concretas de WindowImp suportam diferentes sistemas de janela. A subclasse XwindowImp suporta o sistema X Window: class XWindowImp : public WindowImp { public: XWindowImp(); virtual void DeviceRect(Coord, Coord, Coord, Coord); // remainder of public interface... private: // lots of X window system-specific state, including: Display* _dpy; Drawable _winid; // window id GC _gc; // window graphic context }; essas subclasses implementam operações WindowImp em termos de primitivas de sistema window. 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); }
usos conhecidos ver GoF; Padrões Relacionados um Abstract Factory pode criar e configurar um padrão Bridge específico; o padrão Adapter é dirigido para fazer classes não relacionadas trabalharem juntas. Isso acontece em geral depois de finalizado o projeto dos sistemas Bridge, por outro lado, é usado desde o início em um projeto para que abstrações e implementações variem de modo independente.