Design Patterns A adoção dos padrões terá um efeito profundo e duradouro sobre a forma de escrevermos programas Ward Cunningham e Ralph Johnson Design Patterns • Conhecer os princípios OO não faz de você um bom projetista OO • Bons projetos OO são reutilizáveis, extensíveis e fáceis de manter • Os padrões mostram como construir um projeto OO com estas qualidades • Os padrões mostram soluções OO comprovadamente eficientes Design Patterns • Os padrões não são uma biblioteca de código. Eles fornecem soluções genéricas para problemas de projeto. Você tem de aplicá-los a sua aplicação específica. • Os padrões não são inventados, eles são descobertos • A maioria dos padrões aborda questões relativas a proteção contra variações • A maioria dos padrões permite que parte do sistema varie independentemente de todas as outras partes Design Patterns • Freqüentemente tentamos extrair e encapsular aquilo que varia em um sistema • Os padrões fornecem uma linguagem compartilhada que permite maximizar o valor da sua comunicação com outros desenvolvedores Design Patterns O Adaptador O Adaptador • O Adaptador converte a interface de uma classe em uma outra interface esperada pelo cliente. • O Adaptador permite que classes com interfaces incompatíveis trabalhem em conjunto o que, de outra forma, seria impossível O Adaptador O Adaptador O Adaptador O Adaptador O código fonte Ver arquivo Design Patterns\Adaptador\DadoNormal.java Factory O problema da Pizzaria: uma implementação pobre O código fonte Ver arquivo Design Patterns\Factory\ImplementacaoPobre\Pizza.java Uma fábrica simples O código fonte Ver arquivo Design Patterns\Factory\SimpleFactory\Pizza.java O método fábrica O método fábrica • Define uma interface para criação de um objeto, mas deixa as subclasses definirem que classe instanciar • O pattern "Factory Method" permite a uma classe delegar a instanciação às subclasses Aplicações • Uma classe não pode antecipar a classe de objetos que deve ser criada • Uma classe quer que suas subclasses especifiquem os objetos que ela cria • Classes delegam responsabilidades para uma dentre várias subclasses auxiliares, e deseja-se localizar o conhecimento de qual subclasse auxiliar implementa a delegação O método fábrica Conseqüências • Provê ganchos para as subclasses • Conecta hierarquias de classes paralelas quando há delegação O código fonte Ver arquivo Design Patterns\Factory\FactoryMethod\Pizza.java Fábrica Abstrata Fábrica Abstrata • Provê uma interface para a criação de famílias de objetos relacionados ou dependentes sem especificar suas classes concretas Aplicações • Um sistema deve ser independente de como seus elementos são criados, compostos e representados • Um sistema deve ser configurado para trabalhar com uma única família dentre múltiplas famílias de produtos • Uma família de produtos relacionados é projetada para ser usada em conjunto, e há a necessidade de reforçar essa restrição • Se quer criar uma biblioteca de classes de produtos, revelando apenas suas interfaces e não suas implementações Uma fábrica abstrata Conseqüências • Isola as classes concretas • Facilita a troca de famílias de produtos • Prove consistência entre produtos • Facilita o suporte a novos tipos de produtos O código fonte Ver arquivo Design Patterns\Factory\AbstractFactory\Pizza.java Singleton Singleton • Garante que uma classe tenha apenas uma instância, ou um número controlado de instâncias, e provê um ponto de acesso global a ela(s). Aplicação • É usado quando: • deve haver exatamente uma única instância de uma classe, e ela deve estar disponível a todos os clientes a partir de um ponto de acesso bem definido • quando se deseja que a única instância possa ser estendida por herança, e os clientes serem capazes de utilizar essa instância estendida sem terem de modificar o seu código Estrutura Conseqüências • Acesso controlado à instância única • Espaço de nomes reduzido • Permite refinamento de operações e representação via especialização • Permite um número variável de instâncias • Maior flexibilidade do que em operações de classes O código fonte Ver arquivo Design Patterns\Singleton\Pizza.java Strategy Strategy • O padrão Strategy define uma família de algoritmos intercambiáveis e encapsula cada um deles fazendo com que eles possam ser permutáveis. • O padrão Strategy permite que os algoritmos variem independentemente dos clientes que os utilizam Aplicações • Usado quando muitas classes relacionadas diferem apenas em alguns de seus comportamentos • O padrão Strategy provê uma maneira de configurar uma classe com um entre vários comportamentos possíveis Estrutura Trocando o comportamento em tempo de execução O código fonte Ver arquivos Design Patterns\Strategy\ImplementacaoPobre\Teste.java Design Patterns\Strategy\ImplementacaoMelhor\Teste.java Design Patterns\Strategy\ComportamentoDinamico\Teste.java Iterator Iterator • Provê um modo de acessar seqüencialmente elementos de um objeto agregado sem expor sua representação básica Aplicações • Serve para acessar o conteúdo de um objeto agregado sem expor sua representação interna • Permite suportar múltiplas varreduras de objetos agregados • Provê uma interface uniforme para varrer diferentes estruturas agregadas de forma polimórfica Estrutura Conseqüências • Simplifica a interface do agregado • Mais de um caminho pode estar pendente em um agregado O código fonte Ver arquivos Design Patterns\Iterator\ImplementacaoPobre\Teste.java Design Patterns\Iterator\ImplementacaoMelhor\Teste.java Composite Composite • O padrão a ser usado quando você tem coleções de objetos com um relacionamento todo-parte e você quer ser capaz de tratar estes objetos uniformemente • O padrão Composite fornece uma estrutura para armazenar tanto objetos individuais como coleções destes objetos • O padrão Composite permite aos clientes tratar objetos individuais e coleções de objetos uniformemente Composite Exemplo empresa dptoA Alberto dptoB Antonio Brito dptoC Batista dptoB1 Bento Carlos Bezerra Cardoso Composite • Define uma hierarquia de classes que consiste de objetos individuais (Leaf) e objetos compostos (Composite). • Um elemento da árvore é qualquer objeto na estrutura do Composite. Elementos podem ser objetos individuais ou objetos compostos. Objetos compostos, por sua vez, podem ser constituídos de objetos individuais e outros objetos compostos, e assim por diante. • Em qualquer ponto do código cliente em que se espera um objeto individual, também pode ser usado um objeto composto. Composite • O cliente pode tratar estruturas compostas e objetos individuais uniformemente. • Os clientes normalmente não sabem (e não devem se preocupar) se eles estão tratando com um objeto individual ou composto. • Permite a simplificação do código do cliente, porque evita escrever funções que tenham que testar o tipo das classes que definem a composição. Composite • Torna-se mais fácil adicionar novos tipos de componentes: basta que eles implementem a interface de um elemento da árvore. • Novas definições das subclasses "Leaf" ou "Composite" trabalham automaticamente com as estruturas existentes e o código do cliente. • Os clientes não precisam ser modificados devido a criação de novas classes que implementem a interface. O código fonte Ver arquivos Design Patterns\Composite\Simples\Teste.java Design Patterns\ Composite\Sofisticada2\Teste.java Facade Facade • Provê uma interface unificada para um conjunto de interfaces em um subsistema. • Define uma interface de mais alto nível que torna mais fácil o uso do subsistema. Aplicações • Oferecer uma interface simples para um subsistema complexo • Existem muitas dependências entre clientes e as classes de implementação de uma abstração. • A introdução de um "Façade" irá desacoplar o subsistema dos clientes dos outros subsistemas, promovendo assim, a independência e portabilidade desses subsistemas. Aplicações • Quando se deseja subsistemas em camadas. • Use um "Façade" para definir um ponto de entrada para cada nível do subsistema. Se os subsistemas são dependentes, então pode-se simplificar a dependência entre eles fazendo com que eles se comuniquem uns com os outros unicamente através dos seus "Façades". A Biblioteca: Uma implementação pobre A Biblioteca: Uma implementação pobre A Biblioteca: Uma implementação melhor A Biblioteca: Uma implementação melhor Conseqüências • Isola os clientes dos componentes do subsistema, reduzindo desse modo o número de objetos com que o cliente interage, fazendo com que o subsistema seja muito mais fácil de se usar. • Ajuda a estruturar o sistema em camadas. • Promove um acoplamento fraco entre o subsistema e seus clientes. • Geralmente os componentes de um subsistema são fortemente acoplados. Um baixo acoplamento entre subsistemas permite que se varie os componentes de um subsistema sem afetar seus clientes. O Código Fonte Ver arquivos Design Patterns\Facade\ImplementacaoPobre\Usuario.java Design Patterns\ Facade\ImplementacaoMelhor\Usuario.java Observer Observer • O padrão Observer define uma relação um para muitos entre objetos • O objeto Observado atualiza os Observadores utilizando uma interface comum. • O objeto Observado e os Observadores são fracamente acoplados na medida em que o objeto Observado não conhece os Observadores e nada sabe sobre eles a não ser que eles implementam a interface Observador. Observer • O objeto observado pode enviar o seu estado aos observadores (push) ou disponibilizar métodos de acesso para seus dados (pull). Pull é geralmente considerado mais correto. • Seu programa não deve confiar em que as notificações aos observadores ocorram numa dada ordem. • Java tem várias implementações do padrão Observer, incluindo o Observer genérico java.util.Observer Um exemplo Uma implementação ruim Codificando para uma implementação concreta, não temos como acrescentar novas apresentações sem modificar o programa Ainda uma implementação ruim: Usando um Objeto de Transferência de Dados As interfaces Observador e Observavel Usando as interfaces Java Observer e Observable Usando as interfaces Java Observer e Observable com métodos pull