Design-Patterns - Guia Rapido
-
Upload
roberto-lima -
Category
Documents
-
view
202 -
download
6
Transcript of Design-Patterns - Guia Rapido
Guia de consulta rápida
Design Patterns
Herval Freire de Albuquerque Júnior
Versão 0.5
Introdução
A Orientação a Objetos foi um dos grandes saltos de paradigma no campo do projeto e desenvolvimento de sistemas de software, e trouxe consigo uma gama de novas idéias e conceitos que facilitaram a análise e formalização dos sistemas. Com a ampla adoção da Orientação a Objetos, entretanto, surgiram uma infinidade de situações-problema: modelagens que levavam à queda de performance, sistemas inflexíveis graças a modelagens errôneas e códigos de difícil manutenção.
Foi para reduzir o impacto destes problemas e incentivar a adoção de modelagens de qualidade aceitável, surgiram os Padrões de Projeto – soluções documentadas para problemas comuns encontrados no processo de modelagem de um sistema.
De maneira inversa, o conceito de Anti-Patterns enumera o conjunto de soluções e processos que tendem a piorar os problemas de desenvolvimento. De decisões gerenciais a detalhes de implementação de funcionalidades, os anti-patterns mostram diversas situações que causam dor-de-cabeça aos analistas, gerentes e desenvolvedores e propõem soluções para estes problemas, de forma a salvar o projeto antes que tudo venha a fugir do controle.
O conhecimento aprofundado de padrões e contra-padrões é uma necessidade inerente a todo profissional que deseje aventurar-se no mundo do desenvolvimento de software. Munida de um conjunto de regras e anotações feitas por profissionais que já enfrentaram problemas similares, a equipe de desenvolvimento encontrará a melhor forma de resolver situações que outrora tomariam tempo ou mesmo levariam ao fracasso do projeto.
Sobre este Guia de Consulta
O conteúdo deste guia de consulta rápida resume e enumera uma série de teorias e modelos propostos por diversos autores de renome do ramo da Engenharia de Software. O catálogo de padrões e anti-patterns disposto neste livro contém soluções registradas por seus devidos autores e apenas resume as principais idéias e métodos de forma a ser uma referência concisa de idéias, de forma que a referência aos autores de cada padrão encontra-se ao final da publicação. Para maior aprofundamento em quaisquer tópicos mostrados neste livro, consulte os livros dos respectivos autores.
Padrões de Projeto (Design Patterns)
De maneira simplificada, um padrão é a documentação de um problema conhecido e sua solução em um determinado contexto. Um padrão apresenta uma solução para um problema comum em um determinado contexto. A solução é apresentada de maneira abstrata e descreve como um conjunto de elementos (objetos e classes, no caso dos Padrões de Projeto) pode ser organizado de forma a solucionar o problema da melhor maneira possível. Bons Padrões de Projeto não são somente uma estratégia de como se atacar um problema: eles representam soluções mais confiáveis e comprovadas para problemas em seu contexto específico, induzem à melhor reutilização de componentes de software e a um melhor aproveitamento do sistema através da organização de seus recursos.
Origens dos Padrões de ProjetoNos anos setenta, Christopher Alexander descreveu em livros as primeiras idéias a
respeito de padrões de projeto nas áreas da engenharia civil e da arquitetura. A idéia de Alexander - construir sistemas arquitetônicos complexos baseados em padrões bem conhecidos e comprovadamente funcionais - foi fonte de inspiração para diversos cientistas da computação, que logo adotaram a idéia de padrões para o desenvolvimento de software.
Originados no final dos anos 80, os padrões de projeto para a engenharia de software foram fruto do trabalho paralelo de vários autores: Ward Cunningham e Kent Beck desenvolveram um conjunto de padrões para desenvolvimento de aplicações em SmallTalk, enquanto Jim Coplien desenvolvia, no mesmo período, um catálogo de padrões para C++, conhecidos como idiomas.
Os padrões em software foram popularizados realmente com o lançamento do livro Design Patterns: Elements of Reusable Object-Oriented Software, de Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides (conhecidos como “Gang of Four”, ou simplesmente GoF). O livro - uma coletânea de padrões advindos de diversos autores, lançada em 1994.
Motivação para Utilização de PadrõesExistem diversos argumentos a favor da adoção de Padrões de Projeto na modelagem
de sistemas:• A adoção de padrões enriquece a documentação do projeto e dá um significado
semântico a construções do sistema, permitindo o rápido entendimento de estruturas baseadas no conceito fundamentado pelos padrões;
• Os padrões promovem a reutilização de código;• Os padrões reduzem o tempo necessário para a adaptação a uma determinada
biblioteca ou estrutura: tendo em vista que certos padrões de projeto foram adotados, é mais fácil compreender a organização do subsistema
Tipos de PadrõesDe acordo com o livro Patterns of Software Architecture, podemos dividir os padrões em
três categorias:
• Padrão de Arquitetura (Architectural Pattern) - esquema de organização estrutural de sistemas, incluindo regras para organizar os relacionamentos entre subsistemas e definir suas responsabilidades. Estes padrões afetam as propriedades globais de um sistema e sua organização como um todo.
• Padrão de Projeto (Design Pattern) - um esquema de refinamento de subsistemas e componentes do software, e dos relacionamentos entre eles. Os Padrões de Projeto descrevem situações que se repetem, e soluções para problemas em contextos específicos. Segundo Erich Gamma, os Padrões de Projeto podem ser classificados ainda em famílias de padrões relacionados:
o Padrões de Criação (Creational patterns) - padrões que abstraem o processo de instanciação de objetos. Eles ajudam a tornar modular e flexível a criação, composição e representação de objetos do sistema.
o Padrões Estruturais (Structural patterns) - padrões que trabalham a forma como classes e objetos são compostos em estruturas maiores. Estes padrões lidam com formas de adaptação e interfaceamento entre componentes de uma estrutura maior.
o Padrões Comportamentais (Behavioral patterns) - padrões que definem a atribuição de responsabilidades entre objetos e a correta implementação de algoritmos. Estes padrões lidam com as interações dinâmicas entre grupos de classes e objetos, de forma a facilitar o entendimento fluxos de dados complexos.
• Idioma (Idiom) - um padrão de baixo nível, específico a uma linguagem de programação.
Catálogo de padrõesNo catálogo de Padrões a seguir, a descrição dos padrões tem a seguinte forma:
• Nome e Classificação – Um identificador do conceito e da essência do padrão, que permitirão identifica-lo com facilidade;
• Objetivo – O que faz o padrão e que problemas ele visa atacar;
• Solução – Seqüência de passos necessários para a implementação e utilização de um padrão dado;
• Diagramas - Representação gráfica do padrão utilizando a técnica de modelagem de objetos, utilizando notação UML;
• Conseqüências – Os resultados, pontos fortes e fracos advindos da adoção do padrão;
• Padrões relacionados - Outros Design Patterns que possuem alguma relação com o padrão exposto.
Abstract FactoryCreational Pattern
Objetivo: prover uma interface que permita a criação de grupos de objetos relacionados ou dependentes sem especificar suas classes concretas.
Solução:•Crie uma interface Abstract Factory com Factory Methods para criação de cada tipo de classe Product a ser instanciada.•As subclasses da Abstract Factory implementam os métodos de criação e definem como objetos específicos (SpecificProducts) devem ser instanciados.
Diagramas:Diagrama de Classes
SpecificFactory
FactoryMethodX()FactoryMethodY()
SpecificProduct
SpecificProductY
AbstractFactory
FactoryMethodX()FactoryMethodY()
ProductY
ProductX
Client
Consequências:•Mantém o sistema (cliente) isolado da forma como seus produtos (Products) são criados, compostos e representados.•Projeta um sistema capaz de trabalhar com várias famílias de produtos (SpecificFactories diversas) sem grandes mudanças no código.•Força a utilização em conjunto de uma família de objetos.
•Criação de novos produtos é dificultada, pois os tipos de produtos são fixados pela Abstract Factory: novos produtos requerem novos métodos de fabricação (Factory Methods), o que requer modificação em todas as subclasses da Abstract Factory (todas as SpecificFactories implementadas).
Padrões Relacionados:Uma Abstract Factory é geralmente implementada utilizando Factory Methods ou Prototypes. Fábricas geralmente possuem uma única instância, sendo construídas utilizando o padrão Singleton. O padrão Builder pode substituir uma Abstract Factory ou ser utilizado em conjunto com a mesma em diversas situações.
AdapterStructural Pattern
Objetivo: Converter a interface de uma classe em uma outra interface esperada pelo cliente ou modificá-la para permitir correta utilização no sistema.
Solução:•Crie uma classe abstrata que forneça os métodos de que o cliente necessita (Interface),•Crie uma subclasse adaptadora (Adapter) que estenda a interface abstrata,•Faça a classe adaptadora (Adapter) estender também a classe-alvo (Target) através de herança múltipla ou faça com que a adaptadora receba uma instância da classe-alvo (composição),•Sobrescreva os métodos da classe de interface na classe adaptadora para invocá-los na classe-alvo.
Diagramas:Diagrama de Classes (utilizando herança múltipla)
Adapter
request()
Target
specifi cRequest()
Interface
request()
Client
implementation
request() { specificRequest()}
Diagrama de Classes (utilizando composição)
Interface
request()
Cl ien t
Adapter
request()
Target
specifi cRequest()
+adaptee
request() { adapteee.specificRequest()}
Conseqüências:•Minimiza o número de novos objetos requeridos,
•Força objetos (targets) a se comportar de acordo com um padrão já definido (interface),•A classe adaptadora pode sobrescrever funcionalidades da classe-alvo,•A implementação utilizando herança múltipla não permite que sejam adaptadas subclasses da classe-alvo (diferentemente da implementação por composição)
Padrões Relacionados:O padrão Bridge tem estrutura similar ao Adapter, apesar do objetivo diferenciado (separar interface de implementação). O padrão Decorator acrescenta funcionalidades a um objeto sem modificar sua interface, tornando-o mais natural que o Adapter para uso na aplicação. Proxy também define um representante para outro objeto sem mudar sua interface.
BridgeStructural Pattern
Objetivo: Desacoplar uma abstração de sua implementação para que as duas partes possam variar independentemente.
Solução:•Crie uma classe de implementação (Implementor) que defina uma interface pública,•Crie subclasses da implementação para cada tipo de implementação desejado,
•Creia uma classe de abstração (Abstraction) que mantenha uma associação com a implementação e disponibilize um conjunto de funções para acessar as operações,•Sempre que for necessário utilizar uma implementação, crie subclasses concretas da abstração.
Diagramas:Diagrama de Classes
RefinedAbstraction
ConcreteImplA
operationImpl()
ConcreteImplB
operationImpl()
Implementor
operationImpl()
Abstraction
operation()
+impl
operation() { impl.operationImpl()}
Conseqüências:•Evita acoplamento permanente entre abstrações e implementações•Esconde a implementação de uma abstração do cliente•Permite que uma mesma implementação sirva para várias abstrações de forma transparente ao cliente•Mudanças na implementação não afetam diretamente o cliente•Tanto abstrações quanto implementações devem ser estendidas por herança
Padrões Relacionados:Um Brigde pode ser construído utilizando-se um Abstract Factory.
BuilderCreational Pattern
Objetivo: Separar a construção de objetos complexos de sua representação, de forma que um mesmo processo de construção possa criar diversas representações distintas.
Solução:•Crie uma classe abstrata Builder que implemente Factory Methods para construção de cada parte de um componente•Extenda a classe Builder e implemente os Factory Methods na subclasse (SpecificBuilder)
•Utilize a classe Diretora (Director) para invocar os métodos de criação de partes definidos pela classe Builder e retornar a estrutura completa do objeto para o cliente.
Diagramas:Diagrama de Classes
SpecificBuilder
BuildPartX()BuildPartY()GetResult()
SpecificProduct
Builder
BuildPartX()BuildPartY()
Director
Build()
para cada objeto obj na estrutura { se obj.type = PartX entao Builder.BuildPartX
se objtype = PartY entao Builder.BuildPartY}
Diagrama de Seqüência
Client Director SpecificBuilder
new SpecificBuilder()
new Director(specificBuilder)
Build() BuildPartX()
BuildPartY()
GetResult()
Consequências:
•Mantém o algoritmo de criação de objetos complexos independente das partes e de como elas são montadas•Permite que o processo de construção possa gerar diferentes representações para o objeto construído através de SpecificBuilders distintos.•Mantém o algoritmo de montagem de objetos complexos separado do código do cliente
Padrões RelacionadosO padrão Abstract Factory pode ser adotado em substituição ao Builder, quando o objeto que se deseja instanciar não tiver uma estrutura muito complexa. Builders são geralmente utilizados para produzir Composites.
Chain of ResponsibilityBehavioral Patterns
Objetivo: Evitar acoplamento entre emissor e receptor de uma mensagem permitindo que mais de um objeto possa responder à requisição. Encadeia os objetos recebidos e desloca-os através da corrente até que alguém possa manipula-lo.
CommandBehavioral Pattern
Objetivo: Encapsular uma requisição como um objeto, permitindo chamadas com parametrização de diferentes requisições encapsuladas em objetos
CompositeStructural Pattern
Objetivo: Compor objetos em uma estrutura de árvore de forma a representar hierarquias “parte-todo” de forma que o cliente possa tratar partes e o todo de maneira semelhante sem precisar conhecer a diferença entre composições e nós.
Solução:•Crie uma classe abstrata componente (Component) que defina a interface para todos os objetos da árvore e implemente comportamento comum•Estenda a classe componente e crie uma classe de composição concreta (Composite) que implemente o comportamento necessário para manter e acessar coleções de nós-filhos•Estenda a classe componente e crie uma classe para representar nós que não comportem outros objetos (Leafs)
Diagramas:Diagrama de Classes
Leaf
operation()
Client
Component
add(Component c)remove(Component c)getChild(identifier)operation()
Composite
add(component c)remove(Component c)getChild(identifier)operation()
+childrenoperation() { for each child in children { child.operation() }}
Conseqüências:•Permite ao cliente tratar partes de um todo de maneira semelhante•O cliente pode executar as operações definidas pelo componente nos nós ou nos compositores sem precisar saber o tipo do elemento em uso•Define uma hierarquia que permite a associação em árvores na forma 1-para-N•Permite a adição de novos componentes com facilidade, bastando extensões da classe compositora ou nó. Isto também é uma desvantagem, já que se torna difícil restringir a adição de novos componentes na hierarquia.
Padrões Relacionados:Iterators podem ser utilizados para percorrer Composites. O padrão Flyweight permite compartilhar componentes. Visitor localiza operações e comportamento que de outra forma, seriam distribuídos entre Composites e folhas (Leafs). O padrão Decorator é geralmente utilizado em conjunto com o Composite em diversos casos. Chain of Responsability utiliza-se com freqüência de composições para implementar comportamento.
DecoratorStructural Pattern
Objetivo: Adicionar responsabilidades a um objeto dinamicamente, sem necessidade de criação de subclasses e de maneira que seja possível remover ou variar responsabilidades facilmente
Solução:• Crie uma superclasse decoradora (Decorator) que estenda o componente (Component)
que será decorado e que receba como argumento um componente decorado,• Implemente o método de decoração na classe decoradora de forma a executar o
mesmo método na classe decorada,• Crie subclasses da decoradora (ConcreteDecorator), sobrecarregando o método de
decoração de forma a chamar o método da classe-mãe e em seguida adicionar novo comportamento.
Diagramas:Diagrama de Classes
ConcreteComponent
operat ion()
Decorator
operation()
Client Component
+component
ConcreteDecoratorA
operation()newOperation()
ConcreteDecoratorB
operation()
operation() { component.operation()}
Conseqüências:• Permite a construção de diversas combinações e variações de responsabilidades• A classe componente não precisa ter conhecimento da existência do decorador• Permite adição de comportamento especial a classes previamente existentes sem
utilização de herança• Geralmente leva a um sistema com um grande número de classes pequenas, com
poucas funcionalidades específicas.
Padrões Relacionados:Adapter adiciona funcionalidade a uma classe, porém permite a modificação de sua interface. Um Decorator pode ser visto como um Composite com um só componente. Strategy permite modificar o funcionamento dos objetos, enquanto Decorator modifica sua aparência.
Factory MethodCreational Pattern
Objetivo: Definir uma interface para criação de um objeto e deixar que subclasses decidam o que instanciar.
Solução:•Crie um Factory Method na classe Creator, com a finalidade de instanciar um objeto (Product). Este método pode implementar uma funcionalidade padrão ou ser definido como abstrato.•Subclasses da classe Creator sobrescrevem o Factory Method e instanciam um produto específico (SpecificProduct) da maneira desejada (o SpecificProduct deve ser subclasse de Product).•Opcionalmente, passe um parâmetro para o Factory Method especificando o tipo de produto a ser instanciado.
Diagramas:Diagrama de Classes
ConcreteCreator
FactoryMethod()
ConcreteProduct
AnyOperat ion() { ... Product p = FactoryMethod() ...}
FactoryMethod() { return new ConcreteProduct()}
Creator
FactoryMethod()AnyOperation()
Product Cl ient
Consequências:•Elimina a necessidade de associação a classes específicas (SpecificProducts) na aplicação.•Conecta hierarquias de objetos paralelas.•Garante mais flexibilidade na criação de objetos do que o processo convencional de instanciação.•Para utilizar-se de um novo tipo de SpecificProduct, o usuários deve criar também uma nova subclasse criadora (SpecificCreator), aumentando o número de classes do sistema.
Padrões Relacionados:Abstract Factories geralmente utilizam Factory Methods. Factory Methods são um tipo especial de Template Methods. Em algumas situações, o padrão Prototype substitui o Factory Method.
FaçadeStructural Pattern
Objetivo: Prover uma interface de alto nível para um subsistema complexo e composto de vários objetos e operações, simplificando seu uso e ocultando detalhes de implementação.
Solução:• Clientes comunicam-se com o subsistema através dos métodos definidos na fachada
(Facade) – ele não deve acessar os objetos do subsistema diretamente.• O subsistema geralmente não tem conhecimento da classe cliente ou mantém
referência ao objeto fachada nem do cliente.
Diagramas:Diagrama de Classes
ClientFacade
operation()
Conseqüências:• Reduz a complexidade de um subsistema, reduzindo o número de classes que o cliente
necessita utilizar,• Promove o desacoplamento entre o cliente e o subsistema, permitindo que as classes
do subsistema sejam modificadas sem impactar o sistema cliente,• Reduz o número de objetos com quem o cliente deve lidar.
Padrões Relacionados:Facades podem ser substituídas por Mediators em alguns casos. Elas são geralmente implementadas utilizando-se o padrão Singleton. Podem-se utilizar Abstract Factories quando se deseja construir um subsistema que necessite de configurações específicas de plataforma ou varie sua representação interna
FlyweightStructural Pattern
Objetivo: Utilizar compartilhamento para suportar um grande número de objetos
InterpreterBehavioral Pattern
Objetivo: Definir uma representação para a gramática de uma linguagem dada e interpretar a representação de forma a processar sentenças na linguagem
IteratorBehavioral Pattern
Objetivo: Prover uma via de acesso a conjuntos de objetos agregados sem expor sua representação
Prototype Creational Pattern
Objetivo: Especificar o tipo de objeto a ser criado utilizando uma interface protótipo e criar novos objetos copiando esta instância.
Solução:•Crie uma classe Product que defina um método abstrato de clonagem.
•Crie subclasses específicas de produtos (SpecificProducts) que implementam o método de clonagem e retornam uma cópia de si mesmas.•Durante a inicialização do sistema ou em algum momento adequado, crie uma instância “protótipo” de cada produto específico (SpecificProduct).•Sempre que for necessária uma instância de um SpecificProduct, clone o objeto protótipo utilizando o método de clonagem e utilize o objeto retornado.
Diagramas:Diagrama de Classes
SpecificProduct
clone()
Product
clone()
Client
operation()
prototype
operation() { Product p = Product.clone()}
Consequências:•Permite a escolha de que classe instanciar em tempo de execução.•Útil quando a duplicação de objetos com informações de estado é mais apropriada do que um novo processo de instanciação e configuração de estado.•Reduz ou elimina a necessidade de implementação de hierarquias de Factories paralelas às hierarquias de Produtos.
SingletonCreational Pattern
Objetivo: Garantir que uma classe possua apenas uma instância e prover um ponto de acesso global a ela
Solução:•Declare construtores protegidos ou privados na classe Singleton.
•Declare um atributo interno à classe Singleton que seja da mesma classe do objeto em questão.•Declare um método de acesso estático ao objeto responsável Singleton por inicializá-lo se este for nulo e retorna-lo ao cliente.•Declare os demais métodos da classe normalmente.
Diagramas:Diagrama de Classes
operation() { Singleton s = Singleton.getInstance()}
static getInstance() { return single;}
Client
operation()
Singleton
Singleton single
sta tic getInstance()singletonOperation()
Consequências:•Garante que somente uma instância da classe será criada•Controla o acesso à instância do objeto
Padrões Relacionados:Abstract Factories, Builders e Prototypes podem ser implementadas utilizando-se Singletons. Em ambientes com múltiplas linhas de execução (Multi-Threading), o padrão Double Checked Locking é usualmente utilizado. Quando são necessárias várias instâncias controladas de um objeto, utilize o padrão Multiton.
MediatorBehavioral Pattern
Objetivo: Define um objeto que encapsula como um conjunto de objetos deve interagir. O mediador impede que objetos se referenciem explicitamente e permite trocar as interações entre eles de maneira independente
MementoBehavioral Pattern
Objetivo: Capturar e externalizar o estado interno de um objeto sem violar encapsulamento, de forma que o estado possa ser recuperado posteriormente.
ObserverBehavioral Pattern
Objetivo: Definir um relacionamento um-para-muitos entre objetos, de forma que todos os objetos dependentes são notificados e atualizados automaticamente quando o estado do objeto observado mudar.
Solução:• Crie uma interface observadora (Observer) que defina o método de notificação de
atualização,• Crie uma classe notificadora (Subject) que defina uma estrutura capaz de armazenar
referência a objetos do tipo da classe observadora. Crie métodos para adicionar e remover observadores à notificadora.
• A cada evento de mudança de estado do notificador, chame o método adequado dos objetos que tenham se registrado como observadores.
Diagramas:Diagrama de Classes
Observer
update()
Subjec t
add()remove()notifyAllObservers()request()
0..*0..*
+observers
RealSubject
request()
RealObserver
update()
noti fyAl lObservers() { for each observer in observers { obs erver.update() }}
Conseqüências:• O objeto notificador tem pouco conhecimento sobre os objetos observadores,• Objetos podem ser facilmente adicionados ou removidos como receptores de
notificações,• Notificações de atualização são facilmente propagadas a todos os interessados
Padrões Relacionados:Mediator pode ser utilizado para controlar ou restringir as notificações.
ProxyStructural Pattern
Objetivo: prover um procurador para mediar o acesso a outro objeto.
Solução:• Crie uma classe de conceito abstrata (Subject) que defina a interface pública para
realizar as operações necessárias• Crie uma subclasse da classe de conceito que implemente realmente as operações da
interface (RealSubject)• Crie uma subclasse da classe de conceito (Proxy), que será responsável por instanciar a
classe de implementação real e direcionar requisições para ela.
Diagramas:Diagrama de Classes
request() { realSubject.request()}
Client Subject
Proxy
request( )
RealSubject
request()
+realSubject
Conseqüências:• A classe procuradora pode adicionar funcionalidades à classe de objeto acessada por
ela• Proxies podem ser utilizados para prover representação local a um objeto em outro
espaço (remote proxy), controlar a criação de objetos caros sob demanda (virtual proxy), proteger acesso ao objeto (protection proxy) ou manter uma referência de forma a realizar operações adicionais sobre um objeto (smart reference)
Padrões Relacionados:Adapter tem funcionamento similar ao Proxy, exceto pelo fato de que o Proxy tem interfaces iguais na classe conceito e no procurador.
StateBehavioral Pattern
Objetivo: Permitir a um objeto alterar seu comportamento quando seu estado interno mudar.
Solução: • Declare uma classe de estado abstrata que defina a interface de operações que devam
variar de acordo com o estado do sistema• Crie uma subclasse da classe de estado para cada estado real do sistema• Mantenha no cliente (contexto) uma referência à classe de estado abstrata• Sempre que o estado do sistema precisar mudar, faça o cliente instanciar uma
subclasse específica da classe de estado• Para cada operação dependente de estado, chame o método adequado a partir do
cliente para executar a operação
Conseqüências: • Objetos de estado podem eliminar a presença de grandes blocos condicionais• Mudança e dependência de estados se torna visível e explícita• Estados podem ser utilizados por outros subsistemas, em especial se não mantiverem
dados
StrategyBehavioral Pattern
Objetivo: Definir e encapsular uma família de algoritmos e torná-los intercambiáveis, de forma que o cliente pode utilizar qualquer implementação independentemente.
Solução: • Crie uma classe de estratégia abstrata que defina a interface comum ao algoritmo• Defina uma subclasse da estratégia para cada implementação do algoritmo e
implemente os métodos definidos na classe abstrata• Mantenha uma referência à estratégia abstrata na classe cliente (contexto)• Utilize no cliente a subclasse adequada da estratégia abstrata sempre que necessário
Conseqüências: • Permite fácil reutilização de famílias de algoritmos ou comportamentos• Garante mais flexibilidade do que estender a classe cliente para modificar seu
comportamento• Evita laços condicionais, substituindo-os por implementações concretas da estratégia• Pode ser utilizado para prover várias implementações de um comportamento similar, de
forma a permitir ajustes de performance• O cliente pode ter que conhecer especificamente a estratégia que deseja utilizar para
selecioná-la• A implementação dos algoritmos pode não requerer todos os parâmetros definidos na
estratégia abstrata, gerando overhead desnecessário
Template MethodBehavioral Pattern
Objetivo: Definir o esqueleto de um algorítmo em uma operação e deferir alguns passos para as subclasses, de forma que as mesmas redefinam alguns passos do algoritmo sem modificar sua estrutura.
Solução: • Quebre a seqüência de operações longas em chamadas a métodos separados
(ganchos), na superclasse modelo• Implemente os métodos-gancho nas subclasses da classe modelo de forma a realizar
operações específicas ou em um ambiente operacional específico
Conseqüências: • Leva a uma estrutura de controle invertida conhecida como o “princípio de Hollywood”
(“don’t call us, we’ll call you”) • Delega a implementação de pontos de um processo a subclasses – um conceito
fundamental na construção de frameworks e bibliotecas de classes
VisitorBehavioral Pattern
Objetivo: Representar uma operação a ser realizada em elementos de uma estrutura de objetos, de forma a poder definir novas operações sem modificar as classes sobre as quais elas operam.
Referências Bibliográficas
Gamma, Helm, Vlissides, Johnson. Design Patterns – Elements of Reusable Object Oriented Software. Addison Wesley, Outubro, 1994.