Baixe o app para aproveitar ainda mais
Prévia do material em texto
10/05/2010 1 Padrões de Projeto Carga Horária 67hs Padrões de Construção Prof. Giuseppe Anthony N. Lima giuseppeanl@gmail.com Instituto Federal de Educação Tecnológica da Paraíba CST – Sistemas para Internet Padrões de Construção • Introdução – Criação de objetos • Métodos especiais denominados construtores public B(int x) { this.x=x; } Padrões de Construção • Construtores Java – Operação declarada com mesmo nome da classe • Pode não ser declarado (construtor default) • Não retorna valor – É uma ação de classe (estático) – Inicializa propriedades do objeto criado – Inicializa hierarquia do objeto criado – Aloca o objeto construído na memória Padrões de Construção • Limitações quanto ao uso de construtores – Cliente pode não ter disponível todos os dados necessários para instanciá-lo – Cliente fica acoplado pois precisa saber qual classe concreta chamar com o new – Cliente de herança pode chamar métodos que precisam de valores ainda não inicializados – Objeto complexo pode necessitar da criação de outros menores – Não há como limitar o número de instâncias Builder • Intenção – "Separar a construção de um objeto complexo de sua representação para que o mesmo processo de construção possa criar representações diferentes." [GoF] Obtém informação necessária em passos antes de requisitar a construção de um objeto. Builder • Separar um objeto complexo de sua representação Objetos Partes Comuns Produto Imóvel Telhado, paredes, piso ConstruçãoTipoCasa ConstruçãoTipoPrédio ... Pizza Molho, massa, recheio PizzaApimentada PizzaDoce ... Texto Caracteres, parágrafo, fonte TextoTipoASCII TextoTipoTex TextoTipoWord ... 10/05/2010 2 Builder • ...de modo que o mesmo processo de construção possa criar diferentes representações Objetos Partes Comuns Representação/ Produto Texto Caracteres, parágrafo, fonte TextoTipoASCII TextoTipoTex TextoTipoWord ... Um objeto builder deverá ser capaz de montar as partes de um respectivo produto E devolver o produto (objeto representado) solicitado pelo cliente Builder • Uso de Builder – Um objeto de interesse de um cliente é convertido ou montado como um produto dotado de características específicas Builder • Exemplo I O cliente informa ao DiretorObra se deseja casa ou prédio pelo construtor. O DiretorObra chama o método public void construir() { construtor.construirPiso(); construtor.construirTeto(); construtor.construirParedes(); } Builder • Exemplo II Como o cliente converte um texto RTF para TeX por exemplo? Builder • Vamos entender melhor... Interface/Classe Abstrata para criação de produtos Produto final criado passo a passo via Director Implementação de Builder que constrói e junta as partes do produto Gerencia a seqüência correta de criação das partes do produto Builder • Conseqüências – Permite variar a representação interna do produto – Algoritmo de construção do produto é independente de sua implementação • Construção em partes! – Substituição de construtores (builders concretos) • Uma mesma interface é utilizada para construir representações diferentes dos mesmos dados • Clientes podem estender essa interface se desejarem criar novas representações ou produtos. 10/05/2010 3 Factory Method • Intenção [GoF] – “Definir uma interface para criar um objeto mas deixar que subclasses decidam qual classe irá instanciá-lo” – “Factory Method permite que uma classe delegue a responsabilidade de instanciamento às subclasses.” Factory Method • Problema – O acesso a um objeto concreto (subclasse) será através de sua interface conhecida (superclasse) • O cliente não pode saber qual o tipo concreto do objeto utilizado • Isso ocorre pois é sabido que os tipos concretos de objetos a serem utilizados pelo cliente podem variar: o código do cliente deve ser compatível com todas essas opções de objetos concretos. – Lembre-se: sempre que utilizamos o new deixamos explicito o tipo concreto do objeto! Factory Method • Por que esconder do cliente qual a implementação concreta? – Quando a classe cliente usa new ele pode quebrar o encapsulamento da interface (acessando métodos de baixo nível) Automóvel auto = new Carro(); O cliente sabe a implementação ou seja o objeto concreto Carro carro = (Carro) auto; Com isso, ele pode quebrar o encapsulamento e acessar métodos que só Carro possui! Factory Method • Por que esconder do cliente qual a implementação concreta? – Quando a classe cliente usa new ele causa uma forte dependência em relação ao objeto! Trace logger = new SystemLog(); Imagine uma aplicação web que utiliza esse código em diversos servlets para realizar logging Como o uso do tipo concreto está evidente em cada classe cliente, o que acontece se quisermos alterar o Trace para FileLog? Factory Method • Imagine uma classe cliente que... – Utiliza um objeto que possui diversas implementações – Supostamente altera a implementação do objeto (dentre as opções de classe concreta do objeto) num futuro próximo SOLUÇÃO Vamos encapsular a criação do objeto especificando sua criação em um objeto Criador/Fábrica separado! Factory Method • Factory Method – Definir uma interface de criação de um objeto que permita... • Que tal interface indique uma subclasse responsável por instanciar esse objeto • Que essa subclasse, que implementa tal interface, realize a instanciação • Que clientes acessem o objeto criado por meio de uma interface mais abstrata – compatível com todas as opções de objetos que o cliente pode usar 10/05/2010 4 Factory Method • Estrutura do Padrão... Factory Method • Exemplo: criar uma Factory Method para nossas classes de Logging Contém o método fábrica Implementa o método fábrica que devolve FileLog Implementa o método fábrica que devolve SystemConsoleLog Interface de alto nível para qualquer produto Trace Factory Method • Outro exemplo... – Nossa aplicação exige a criação de pizzas de diversos sabores //método presente no código do cliente public Pizza orderPizza() { Pizza = new Pizza(); pizza.prepare(); pizza.assar(); pizza.cortar(); pizza.encaixotar(); return pizza; } Oops, presença de new! Factory Method //método presente no código do cliente public Pizza orderPizza(String type) { Pizza pizza; if (type.equals(“cheese”)) { pizza = new CheesePizza(); } if (type.equals(“pepperoni”)) { pizza = new PepperoniPizza(); } ... //para cada tipo de pizza uma verificação e instanciação do tipo correspondente pizza.prepare(); pizza.assar(); pizza.cortar(); pizza.encaixotar(); return pizza; } Ainda há presença de new e se novas pizzas estiverem disponíveis para uso na classe cliente? Factory Method • Mas se o modo como as pizzas forem preparadas (criadas) variar ainda que sejam de um mesmo sabor – Dependendo da região o tipo e quantidade de ingredientes de um sabor pode ser diferente – Ou seja, o modo de criação de um tipo varia com a região • Solução – Criar Fábricas para cada modo de criação! Factory Method 10/05/2010 5 Factory Method • Vantagens – Criação de objetos é desacoplada do conhecimento do tipo concreto do objeto • Conecta hierarquias de classe paralelas • Facilita a extensibilidade • Desvantagens – Cliente ainda deve saber a classe concreta do criador de instâncias Abstract Factory • Intenção – "Prover uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas." [GoF] Abstract Factory • Prover uma interfacepara criar famílias de objetos relacionados ou dependentes? – A interface é uma fábrica de produtos – A fábrica é capaz de criar um conjunto de produtos para um determinado contexto • Conjunto de produtos são as famílias de produtos que são utilizados em um contexto comum Abstract Factory • Abstract Factory – A interface de criação de famílias de objetos possui um conjunto de factory methods para cada produto – Algumas situações • Precisamos criar uma família de componentes de interface (toolbar, botões e menus) de acordo com a plataforma de interface do usuário • Precisamos criar componentes de um jogo de acordo com o grau de dificuldade do mesmo • Precisamos criar uma família de ingredientes de pizza de acordo com a região do cliente Abstract Factory • Arquitetura do padrão Abstract Factory • Quando usar Abstract Factory? – Quando um sistema deve ser independente de como seus produtos são criados, compostos e representados – Quando um sistema deve ser configurado com uma entre várias famílias de produtos – Quando uma família de produtos relacionados foi projetada para uso conjunto e você deve implementar essa restrição – Quando você quer fornecer uma biblioteca de classes e quer revelar sua interface e não sua implementação • Não permita portanto que objetos sejam diretamente criados com new 10/05/2010 6 Abstract Factory X Factory Method • Para pensar... Factory Method Abstract Factory Fábricas utilizam herança para criar os produtos concretos Fábricas utilizam composição para criar famílias de produtos (objetos relacionados pelo cliente em um contexto) As subclasses, fábricas concretas, herdam factory methods para criação de produtos. Cada subclasse decide qual produto irá criar. As implementações de fábricas possuem uma factory method para criar cada membro da família de produtos Se novos produtos forem adicionados basta criar uma nova subclasse Para criar novos produtos a interface deverá ser estendida exigindo alterações nas fábricas existentes Pode implementar código no criador abstrato que manipula tipos concretos criados nas subclasses Métodos nos criadores concretos são somente factory methods que criam produtos. A manipulação dos produtos é de responsabilidade exclusiva do cliente Factory Method & Abstract Factory • Notas de implementação – Tanto para Factory Mehtod quanto para Abstract Factory, é comum a criação de uma método estático que devolve a fábrica concreta a ser utilizada a partir de uma chave que devolve apenas uma instância! • Para evitar que o cliente saiba a interface do criador concreto e que se tenha mais de uma instância de fábrica //classe factory abstrata public static FactoryIF getInstance(String tipo) { //acessa uma coleção de fábricas disponíveis //devolve a fábrica de acordo com o a tipo solicitado } //acesso do cliente AbstractFactory.getFactory(“fábricaA”); Factory Method & Abstract Factory • Se Abstract Factory determina a utilização de uma interface para as fábricas onde você implementaria esse método estático? Olha ele aqui! Prototype • Intenção – "Especificar os tipos de objetos a serem criados usando uma instância como protótipo e criar novos objetos a partir da cópia desse protótipo." [GoF] Prototype • Dicionário – Protótipo: original, modelo, exemplar, versão parcial • Padrão Prototype – Cópia de um objeto a partir de um objeto modelo Prototype • Algumas razões para criação de objetos a partir de outros – Reaproveitar o estado existente de um objeto – Queremos executar algoritmos que alteram um objeto • Em vez de utilizar os dados do objeto original utilizamos sua cópia • Em caso de erro ainda temos o objeto original – Armazenar estados de objetos 10/05/2010 7 Prototype • Como saber se um objeto é um protótipo (modelo de cópia)? – A interface deverá conter o serviço de cópia – A interface identifica que o objeto é copiável Prototype • Arquitetura do Padrão Prototype • Prototype em Java I – Object contém um método privado clone()! – Como usar • Fazer a classe definida como protótipo implementar Cloneable • Sobrepor o método clone() para torná-lo público public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } } Prototype • Prototype em Java II – Limitações • O clone() realiza cópias rasas – Referências do protótipo a outros objetos devem ser copiados também public class Circulo { private Point origem; private double raio; public Object clone() { try { Circulo c = (Circulo)super.clone(); c.origem = origem.clone(); // Point deve ser clonável! return c; } catch (CloneNotSupportedException e) {return null;} } } Memento • Intenção – "Sem violar o encapsulamento, capturar e externalizar o estado interno de um objeto para que o objeto possa ter esse estado restaurado posteriormente." [GoF] Memento • Problema – É preciso guardar informações sobre um objeto suficientes para desfazer uma operação, mas essas informações não devem ser públicas 10/05/2010 8 Memento • Um memento é um pequeno repositório para guardar estado dos objetos – Pode-se usar outro objeto, um string, um arquivo • Memento guarda um snapshot do estado interno de outro objeto, a Fonte – Um mecanismo de Undo irá requisitar um memento da fonte quando ele necessitar verificar o estado desse objeto – A fonte reinicializa o memento com informações que caracterizam seu estado atual – Só a fonte tem permissão para recuperar informações do memento (o memento é invisível para outros objetos) Memento • Use Memento quando – Uma parte do estado (snapshot) de um objeto precisa ser armazenada para que ele possa ser restaurado ao seu estado original posteriormente – Disponibilizar uma interface ara se obter esse estado iria expor detalhes de implementação desse objeto que representa o estado, quebrando o encapsulamento. Memento Memento: objeto que armazena um estado Fonte: objeto que cria um memento para armazenar seu estado anterior Zelador: executa mecanismo de undo Memento • A fonte (originator) – É algum objeto que tem um estado interno • Zelador (caretaker) – Faz algo para a fonte armazenar estados – O zelador pede a fonte um objeto Memento para armazenar – O zelador restaura algum estado solicitando a fonte • Memento – Objeto que guarda um estado interno – O zelador não tem acesso para modificá-lo Memento class Fonte { private String state; public void set(String state) { System.out.println("Originator: Setting state to " + state); this.state = state; } public Object saveToMemento() { System.out.println("Originator: Saving to Memento."); return new Memento(state); } public void undo(Object m) { if (m instanceof Memento) { Memento memento = (Memento) m; state = memento.getSavedState(); System.out.println("Originator: State after restoring from Memento: " + state); } } //continuação da classe Fonte (classe memento é uma inner class) private class Memento { private String state; public Memento(String stateToSave) { state = stateToSave; } public String getSavedState() { return state; } } } 10/05/2010 9 Memento class Zelador { private List<Object> savedStates = new ArrayList<Object>(); public void addMemento(Object m) { savedStates.add(m); } public Object getMemento(int index) { return savedStates.get(index); } } Memento //cliente class MementoExamplo { public static void main(String[] args) { Zelador zelador = new Zelador(); Fonte fonte= new Fonte(); fonte.set("State1"); fonte.set("State2"); zelador.addMemento(fonte.saveToMemento());fonte.set("State3"); zelador.addMemento(fonte.saveToMemento()); fonte.set("State4"); fonte.undo(zelador.getMemento(1)); } } Memento • Implementação – Armazenar estados incrementalmente • Uma aplicação que manipula um bitmap armazena como estado somente os pixels modificados – Armazenar estados com cópia completa • Todos os atributos de um objeto serão copiados e armazenados ainda que alguns não tenham se modificado – Armazenamento em disco • Estados são armazenados em disco pois precisam ser persistidos Memento • Conseqüências – Uso de memento pode ser caro dependendo do número e formato dos estados armazenados – Evita expor propriedades de um objeto para guardar seu valor anterior – Possibilita implementar mecanismos de undo e checkpoint Memento • Exemplo – Temos um livro de endereços – Um livro de endereços possui um conjunto de contatos – Se eliminarmos ou adicionarmos contatos poderemos restaurar o estado do livro de endereços Fonte (Originator) Memento (Estado Interno) Memento //A nossa classe Fonte(Originator) class AddressBook { private ArrayList contacts = new ArrayList(); public Object getMemento() { return new AddressBookMemento(contacts); } public void setMemento(Object object) { if (object instanceof AddressBookMemento) { AddressBookMemento memento = (AddressBookMemento) object; contacts = memento.state; } } private class AddressBookMemento { private ArrayList state; private AddressBookMemento(ArrayList contacts) { this.state = contacts; } } 10/05/2010 10 Memento //Código do Cliente public static void main(String[] arguments) { AddressBook book = new AddressBook(); book.addContact(new ContactImpl("Peter", "Taggart", "Commander", "NSEA Protector", new AddressImpl())); book.addContact(new ContactImpl("Tawny", "Madison", "Lieutenant", "NSEA Protector", new AddressImpl())); book.addContact(new ContactImpl("Dr.", "Lazarus", "Dr.", "NSEA Protector", new AddressImpl())); book.addContact(new ContactImpl("Tech Sargent", "Chen", "Tech Sargent", "NSEA Protector", new AddressImpl())); Object memento = book.getMemento(); book.setMemento(memento); } Quando utilizarmos o AdressBook em uma aplicação maior provavelmente necessitaremos restaurar seu estado em mais de um ponto do código e aí surge: onde coletar os estados de forma que possamos reusar o acesso a estados anteriores em vários pontos do código? Veja que o cliente está tendo a obrigação de organizar o memento: vamos criar uma entidade que zela pelos estados do livro de endereços! Memento //Código do Zelador(Caretaker) public class ZeladorAgendas { private List<Object> estadosSalvos = new ArrayList<Object>; public Object getMemento(int index) { return estadosSalvos.get(index); } public void addMemento(Object o) { estadosSalvos.add(o); } } Zelador não tem acesso ao tipo Memento pois essa classe foi definida internamente na Fonte como private: lembre-se, somente a Fonte tem acesso a Memento e principalmente a serviços que manipulam seu estaodo interno. Por isso a coleção do Zelador é do tipo Object!
Compartilhar