Aula Padroes de Projeto -...
Transcript of Aula Padroes de Projeto -...
� Etapas principais do desenvolvimento de software
� Padrões arquiteturais� Padrões de projeto
1
� Criar aplicações não é apenas escrever código(code and fix)
� Atualmente as aplicações exigemarquiteturas e código cada vez maissofisticados
� Um dos maiores desafios é saber “o que” codificar
2
� Aprender conceitos úteis para o planejamento e construção de aplicações� Flexíveis, eficientes, reutilizáveis e de fácil
manutenção
� Uso de padrões de projeto como soluçõespara problemas recorrentes dentro da programação
3
� C++ é uma linguagem usada comoferramenta de aprendizado pois� Possui um enorme material disponível através de
livros, sites, tutoriais, etc.
� Possui IDEs, depuradores, bibliotecas, etc.
� É multiplataforma: Linux, Windows, Mac OS, etc
4
� No entanto, o principal desafio não é a linguagem C++ ou qualquer outra linguagem
� O desafio é como estruturar sua aplicação:� Decidir quando e quais classes utilizar
5
� Existem vários metodologias, fases, mas em geral as etapas são:� Análise
� Projeto
� Implementação
� Testes
� Não é linear
6
� Se cada fase for bem trabalhada minimiza o risco de alterações na aplicação
� Mudanças essas que poderiam impactarseveramente no cronograma e também no sucesso do projeto
7
� O que a aplicação deve fazer:
� Análise ruim resulta frustração
8
� Uma boa análise deve fornecer umaESPECIFICAÇÃO CLARA que esboça as necessidades do cliente.
� Diferente das outras fases, a análise nãonecessita ter uma aspecto técnico.
9
� O produto gerado pela fase de análise é geralmenteum documento que pode ser:� Uma simples lista de tudo que a aplicação deve ser capaz
de fazer
� Casos de uso que apresentam os requisitos da aplicaçãodemonstrando as possíveis interações que os usuáriosterão com a aplicação
10
� Define “como” será a aplicação� O produto da fase de projeto é um documento
que ajuda a dividir o desenvolvimento da aplicação em etapas menores
11
� Determinação das classes � Responsabilidades de cada classe� Os relacionamentos que cada classe tem com
seus colaboradores� Definição das interfaces fornecidas pela
aplicação (os métodos públicos das classes)
12
� Responsabilidade é essencialmente o que uma classe(ou instância de uma classe) deve ser capaz de realizar
� É geralmente algo que pode ser escrito em umalinguagem de programação, por exemplo:� Criar um formulário de dados, validação estes dados
� Tratar requisições e respostas para e de um serviço de um servidor
� Desenhar uma figura de um modelo de dados� À medida que se definem as responsabilidades das
classes, são feitas: alterações, mudanças, adições de novas classes e outras são descartadas.
13
� Codificar o que foi definido nas fases anteriores
14
� Boas práticas de codificação são um grandebenefício para o desenvolvimento de aplicações
� Melhoram a legibilidade da aplicaçãotornando-a mais fácil de compreender poroutros desenvolvedores de sua equipe� int ano; Mapa cidade; � void obtenhaDadosMapaParaEndereco(DadosEndereco
endereco);
15
� Exemplo de boa prática de programação
16
� Acoplamento forte ou� Acoplamento fraco
� Acoplamento fraco cria aplicações flexíveis e adaptáveis.
� Se objetos são fortemente acoplados, a aplicação torna-se rígida, ou seja, uma mudançaem um objeto pode atingir outros objetos e prejudicar todo o sistema.
17
� Executar testes podem ajudar a determinar se a aplicação roda como esperado e permite detectarpossíveis erros.
� Quem faz os testes?� Testadores � Os próprios desenvolvedores
� De que forma?� Testes manuais� Testes automatizados
18
� Padrões de software que oferecem soluçõesbem-definidas para problemas arquiteturais emum software
� Expressam uma forma de organização estruturalpara um software, que consiste de subsistemas, suas responsabilidades e interrelações
� Em comparação com padrões de projeto, padrões arquiteturais são maiores em escala
19
� Cada camada (tier) é desenvolvida e mantida como um módulo independente
� Conceitualmente a arquitetura em 3 camadas é linear. O padrão MVC é triangular.
20
� Frequentemente mais utilizados em aplicações Web� View: página HTML� Controller: código que reúne dados dinâmicos e gera o
conteúdo dentro do HTML� Model: conteúdo atual, geralmente armazenado em um
banco de dados
21
� Peer-to-Peer (P2P)
� Invocação implícita
� Arquitetura orientada a serviços
� E outros mais.
22
� Um padrão é uma descrição do problema e a essência da sua solução
� Documenta boas soluções para problemas recorrentes � Permite o reuso de conhecimento anterior
documentados em boas práticas
� Deve ser suficientemente abstrato para ser reusado em aplicações diferentes
23
� Algo comprovado que captura e comunica os conhecimentos das melhores práticas
� Descoberto, não inventado
� Soluções Sucintas e de Fácil Aplicação� Capturam, de forma sucinta e facilmente aplicável,
soluções de projeto de programas de computador que foram desenvolvidas e evoluíram com o passar do tempo
24
� Soluções Exaustivamente Refinadas� Resultados de um longo processo de projeto, re-projeto,
teste e reflexão sobre o que torna um sistema mais flexível, reusável, modular e compreensível
� Soluções Compartilhadas� Construídas em grupo
� Através do uso de um vocabulário comum
25
� Os 23 padrões de projeto mais conhecidos foram popularizados pelo livro de E. Gamma, R. Helm, R. Johnson e J. Vlissides� Conhecido como Gang-of-
Four (GoF)
26
� Segundo o seu propósito � De Criação: tratam da criação de objetos
� Estruturais: tratam da composição de classes e objetos
� Comportamentais: tratam das interações e responsabilidades entre classes e objetos
� Segundo seu escopo � Classes: lidam com os relacionamentos entre
classes e subclasses
� Objetos: lidam com os relacionamentos entre objetos
27
� Nome � Um identificador significativo para o padrão
� Descrição do problema � Descrição da solução
� Um template de solução que pode ser instanciado em maneiras diferentes
� Consequências � Os resultados e compromissos de aplicação do
padrão B
28
� Tornam um sistema independente de como seus objetos são criados, compostos e representados
� Estes tipos de padrões ajudam a tornar a aplicação mais flexível, não necessariamentemenor
� Padrões criacionais geralmente delegam a criação de objetos para subclasses
29
� Abstract Factory
� Builder
� Factory Method
� Prototype
� Singleton
30
� Permite a criação de objetos a partir de classes abstratas através do uso de subclasses
� Pode associar duas ou mais hierarquias de classediferentes mas relacionadas entre si
� Muito utilizado na criação de frameworks para definir e manter relacionamentos entre objetos
31
� Uma classe não é capaz de definir os tipos de objetos que deve criar
� Uma classe deseja que suas subclasses especifiquem os objetos que estão criando
� Classes delegam tarefas para uma de váriasclassses auxiliares, e deseja-se saber qualdelas recebeu alguma tarefa para realizar
32
33
� Creator : declara o factory method (método de fabricação) que retorna o objeto da classe Product (produto). Este elemento também pode definir uma implementação básica que retorna um objeto de uma classe ConcreteProduct (produto concreto) básica;
� ConcreteCreator — sobrescreve o factorymethod e retorna um objeto da classe ConcreteProduct;
34
� Product — define uma interface para os objectos criados pelo factory method;
� ConcreteProduct — uma implementação para a interface Product.
35
� Factory method elimina a necessidade de associarclasses específicas de aplicação no código.
� O código lida apenas com a interface Product portantoa mesma pode funcionar com qualquer classes ConcreteProduct definidas pelo usuário
� Exemplo: suponha uma aplicação lida com diversos tipos de documentos� A mesma sabe quando os documentos devem ser
criados, mas não sabem que documentos criar
36
� Factory method elimina a necessidade de associarclasses específicas de aplicação no código.
� O código lida apenas com a interface Product portantoa mesma pode funcionar com qualquer classes ConcreteProduct definidas pelo usuário
� Exemplo: suponha uma aplicação lida com diversos tipos de documentos� A mesma sabe quando os documentos devem ser criados,
mas não sabem que documentos criar
37
� A aplicação construída através de um framework baseado no padrão Factory
Method, suporta a criação de documentos do tipo MeuDocumento.
38
class Aplicacao { protected:
Documento doc; public:
virtual Documento criaDocumento() = 0; void novoDocumento() {
this.doc = this->criaDocumento(); }
void abrirDocumento() { this->doc.abrir(); } };
class Documento {
virtual void abrir() = 0;virtual void fechar() = 0; virtual void gravar() = 0;
};
39
class MinhaAplicacao : public Aplicacao {public:
virtual Documento criaDocumento() { return new MeuDocumento();
} };
class MeuDocumento : public Documento {public:virtual void abrir() { cout << "Documento: Abrir documento!“ << endl; }
virtual void fechar() { cout << "Documento: Fechar documento!“ << endl; }
virtual void gravar() { cout << "Documento: Salvar documento!“ << endl; }
};
40
� O framework é constituído pelas classes abstratas Aplicacao e Documento.
� A aplicação disponibiliza as classes concretas MinhaAplicacao e MeuDocumento.
� A classe MinhaAplicacao é uma implementação da abstração definida pela classe Aplicacao
41
� A chave deste padrão está na declaração do método abstrato criaDocumento, da classe Aplicacao, e na sua utilização pelo método novoDocumento.
� Isso permite que o método novoDocumento crie documentos sem conhecer os detalhes de implementação
� Desta forma, a implementação do método criaDocumento (neste caso situada na classe MinhaAplicacao) varie livremente, para atender os diversos formatos possivelmente suportados.
� Sem que seja necessário modificar o código das classes abstratas.
42
� Nome� Singleton
� Descrição do problema� Uma classe precisa ter uma única instância
� Descrição da solução� Próximo slide
� Consequências� Fácil acesso e gerência de recursos
compartilhados, como variáveis globais
43
� O construtor é privado� O método getInstance() é público e estático
� Retorna a única instância que é guardada em uma variável de classe
44
class Singleton {
private: static Singleton *instance; Singleton() { // construtor privado }
public: static Singleton* getInstance(); void metodo();
};
Singleton* Singleton::instance = NULL;
45
Singleton* Singleton::getInstance() { if(!instance) {
instance = new Singleton(); return instance;
} else {
return instance; }
}
void Singleton::metodo() { cout << "Metodo da classe Singleton" << endl;
}
46
� Possui um atributo que armazena a única instância da classe
� Construtor da classe é privado para evitar criação acidental de outras instancias.
� Única instancia só pode ser obtida pela chamada ao método getInstance() da classe.
47
int main() {
Singleton *sc1,*sc2;
// Singleton objeto; //erro de compilação
sc1 = Singleton::getInstance(); sc1->metodo();
sc2 = Singleton::getInstance(); sc2->metodo();
}
48
� Padrões de projeto estruturais são padrões que lidam com as estruturas do projeto, facilitando a comunicação entre suas entidades.
� Estes padrões, em outras palavras cuidam da estrutura de seu projeto.
� Fazendo analogia com a engenharia civil, estes seriam responsáveis por definir o alicerce da construção bem como a estrutura para sustentá-la
49
� Adapter
� Bridge
� Composite
� Decorator
� Façade
� Flyweight
� Proxy
50
� Uma biblioteca é projetada para ser reusada
� Entretanto, a interface da biblioteca (assinatura dos métodos) pode não ser exatamente a esperada pela aplicação � Não é desejável alterar o código da aplicação
� Não é desejável alterar a interface da biblioteca
51
� Nome� Adapter
� Descrição do problema� Permitir que classes com interfaces incompatíveis
trabalhem juntos� Descrição da solução
� Próximo slide
� Consequências� Reuso de funcionalidades de uma classe sem alterar
sua interface
52
53
� O cliente (Client) precisa de uma funcionalidade
� A funcionalidade já está implementada no Adaptee. Entretanto, os métodos tem assinaturas diferentes.
� A classe Target tem a assinatura do método que o cliente precisa.
� A classe Adapter converte a assinatura do método em Adaptee para aquela que o cliente precisa.
54
class TomadaDeDoisPinos {
public: void ligarNaTomadaDeDoisPinos() {
cout << “Ligado na Tomada de Dois Pinos“ << endl; }
};
class TomadaDeTresPinos {public:
void ligarNaTomadaDeTresPinos() { cout << Ligado na Tomada de Tres Pinos“ << endl;
}}
55
class AdapterTomada : public TomadaDeDoisPinos { private:
TomadaDeTresPinos tomadaDeTresPinos;
public: AdapterTomada(TomadaDeTresPinos tomadaDeTresPinos) {
this->tomadaDeTresPinos = tomadaDeTresPinos; }
void ligarNaTomadaDeDoisPinos() { tomadaDeTresPinos.ligarNaTomadaDeTresPinos();
} };
56
� Tem-se uma classe TomadaDeDoisPinos que deve ser conectada a uma classe TomadaDeTresPinos que possui outros métodos e uma outra interface diferente.
� Usamos um Adapter para poder acessá-la. O Adapterherda da TomadaDeDoisPinos (o seu Target como mostrado no diagrama de classes).
� Dentro do Adapter tem-se o que o cliente precisa que é a TomadaDeTresPinos que será chamado posteriormente no método ligarNaTomadaDeDoisPinos que na verdade está chamando o método ligarNaTomadaDeTresPinos.
57
int main() {
TomadaDeTresPinos *t3 = new TomadaDeTresPinos();
AdapterTomada *a = new AdapterTomada(t3);
a->ligarNaTomadaDeDoisPinos();
}
58
� O cliente faz uma chamada usando a tomada de dois pinos
� Mas na realidade esta chamada está sendo adaptada para uma tomada de três pinos.
� Assim temos duas interfaces que não eram compatíveis entre si conversando normalmente.
59
� Nome� Decorator
� Descrição do problema� Agregar dinamicamente novas responsabilidades
a um objeto� Descrição da solução (Próximo slide)� Consequências
� Maior flexibilidade que herança
� Evita sobrecarregar hierarquia de classes
60
61
� A classe abstrata Component é implementada pela classe concreta ConcreteComponent, que é o objeto no qual será adicionado dinamicamente um novo comportamento.
� As classes Decorator implementam a mesma interface abstrata que o componente que irão decorar.
� Os ConcreteDecorator também podem adicionar mais comportamentos (método addedBehavior() no diagrama ConcreteDecoratorB) ou mais atributos (addedState no diagrama ConcreteDecoratorA).
� Portanto a ideia basicamente é que através dos Decoratorspossamos adicionar comportamentos aos componentes bases (ConcreteComponent).
62
class Janela { // Componentpublic:
virtual void draw() = 0; } ;
class JanelaSimples : public Janela { // ConcreteComponentpublic:
virtual void draw() { cout << “desenha uma janela” << endl;
} };
class JanelaDecorator : public Janela { // Decoratorprotected:
Janela janelaDecorada; public :
JanelaDecorator(Janela janelaDecorada) { this->janelaDecorada = janelaDecorada;
}};
63
� Acima tem-se a implementação da primeira parte do padrão Decorator.
� Nesse exemplo criou-se uma janela simples onde queremos adicionar mais coisas como barras de rolagem, caixas de texto, labels, etc.
� Assim, criou-se também a classe JanelaDecorador que será estendida pelos decoradores que irão inserir propriedades na nossa janela.
64
class DecoradorBarraVertical : public JanelaDecorator { //ConcreteDecorator
private:void drawBarraVertical() {
cout << “desenha uma barra vertical na janela”;}
public: DecoradorBarraVertical(Janela janelaDecorada) :
JanelaDecorator(janelaDecorada) { }
virtual void draw() { drawBarraVertical(); janelaDecorada.draw();
}
};
65
� No código acima um decorador anexa uma barra vertical ao nosso componente principal (JanelaSimples).
� Portanto, anexamos responsabilidades ao nosso componente base. Se quiséssemos criar uma barra horizontal, menus, botões, faríamos outros decoradores para anexar mais responsabilidades.
� Uma situação importante a se observar são as duas chamadas ao método draw(). A chamada a drawBarraVertical() chama ele próprio para pintar na tela a sua própria barra vertical e a outra chamada que veio da superclasse é a responsável por chamar outros decoradores que podem ser anexados na classe.
66
int main() {
Janela *janelaDecorada = new DecoradorBarraVertical(new JanelaSimples());
janelaDecorada->draw();}
� Note que a execução do janelaDecorada.draw() irá chamar o método draw da janela simples combinado com o draw() do nosso decorator.
67
68
Perguntas?
FIM
69