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 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 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
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
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
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
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
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
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
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
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 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
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