• Nenhum resultado encontrado

06 Padroes Singleton AbstractFactory

N/A
N/A
Protected

Academic year: 2021

Share "06 Padroes Singleton AbstractFactory"

Copied!
54
0
0

Texto

(1)

Padrão Singleton

Padrões e Frameworks

Roberto A. Bittencourt Jairo Calmon

(2)

Singleton

• Como a maioria dos programadores organizaria o código para acessar informação de configuração? • Eis um exemplo

public class Config {

public static final String DEFAULT_READ_COMMUNITY_NAME = "public"; public static final String DEFAULT_CONCENTRATOR_RETRIES = "3"; public static final String DEFAULT_CONCENTRATOR_TIMEOUT = "3000";

public static final String DEFAULT_URL_CONSUMER_DATABASE = "jdbc:DBF:////home/jacques/src/celb-database";

}

public class Foo{

// ... facaAlgo(Config.DEFAULT_READ_COMMUNITY_NAME); // ...

(3)

Objetivo

• Assegurar que uma classe tenha uma única

instância e prover um ponto de acesso global

a esta instância

(4)

Motivação

• Algumas classes devem ser instanciadas uma única vez:

– Um spooler de impressão – Um sistema de arquivos – Um Window manager

– Um objeto que contém a configuração de um programa – etc.

• Como assegurar que uma classe possua apenas uma instância e que esta instância seja facilmente acessível?

– Uma variável global deixa a instância acessível mas não inibe a instanciação múltipla

(5)

Motivação

• Uma melhor solução: faça com que a classe em si seja responsável pela manutenção da instância única • Este é o padrão Singleton ("que-possui-apenas-um")

E este também é um dos argumentos para dizer que é um anti-pattern.

(6)

Aplicabilidade

• Use o padrão Singleton quando:

– Deve haver uma única instância de uma classe e esta instância deve ser acessada a partir de um ponto de acesso bem-conhecido

– Quando a instância única deve ser extensível através de subclasses e clientes podem usar instâncias diferentes polimorficamente, sem modificação de código

(7)

Motivação

Mais um motivo para considerar como sendo um anti-pattern:

– “Uma única instância de uma classe que deve ser acessada a partir de um ponto bem conhecido”

– Para alguns é só uma maneira mais bonita de dizer:

• VARIÁVEL GLOBAAAL!!! EBAAAA!!! HUEHUEHUEBR!!111

– Por isso seu uso deve ser bem avaliado

(8)
(9)

Participantes

• Singleton

– Define uma operação getInstance() que permite que clientes acessem sua instância única

• É um método estático (class method)

– Pode ser responsável pela criação de sua instância única

(10)

Colaborações

• Clientes acessam a instância apenas através da

operação getInstance() do Singleton

(11)

Consequências

• Vários benefícios existem:

– Acesso controlado à instância única

• O singleton tem controle sobre como e quando clientes acessam a instância

– Espaço de nomes reduzido

• O Singleton é melhor que variáveis globais, já que as "globais" podem ser encapsuladas na instância única, deixando um único nome externo visível

– Permite refinamento de operações e de representação

• Várias classes Singleton (relacionadas ou não via herança) podem obedecer a mesma interface, permitindo que um singleton

particular seja escolhido para trabalhar com uma determinada aplicação em tempo de execução

(12)

Consequências

– Permite a existência de um número variável de instâncias • É fácil fazer com que o Singleton crie um número fixo, ou um

número máximo de instâncias em vez de apenas uma única instância

• Apenas a implementação interna do Singleton precisa mudar – Mais flexível que métodos estáticos

• Embora possa parecer que podemos fazer o equivalente a um

Singleton com métodos estáticos, lembre que isso não permitiria o polimorfismo:

NomeDeClasse.foo(); // chamada não é polimórfica // ... versus ...

(13)

Considerações de implementação

• Como assegurar que haja uma única instância?

• Uma forma é de não permitir chamadas ao construtor

• Observe que o uso de lazy instantiation é preferível a retornar uma instância estática da classe

– Lazy instantiation pode ser mais rápida se a instanciação/inicialização for lenta

public class Config implements ConfigIF {

private static ConfigIF instânciaÚnica = null;

private Config() {} // o compilador não vai gerar um construtor default público

public static ConfigIF getInstance() { if(instânciaÚnica == null) {

// "lazy instantiation"

instânciaÚnica = new Config(); }

return instânciaÚnica; }

(14)

Anti-pattern?

• Outros problemas que levam alguns a considerarem Singleton como anti-pattern:

– Não é Test-friendly. É difícil realizar testes com o singleton sem ter que reiniciar o estado

– Problemas de sincronização.

• Implementações geralmente defeituosas ou ineficientes

– Uso indiscriminado (muitos usam apenas a “facilidade” de ter uma variável global no código.

– “it is overused, introduces unnecessary restrictions in situations where a sole instance of a class is not actually required, and introduces global state into an application”

• Ver links disponíveis em

http://dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/singleton.htm

(15)

Padrão Abstract Factory

Padrões e Frameworks

Roberto A. Bittencourt Jairo Calmon

(16)

Relembrando o Factory Method

• Na aula do Factory Method, vimos o exemplo do

labirinto.

– Tínhamos uma classe Jogo, com métodos de criação e um método montaLabirinto()

– Tínhamos subclasses de Jogo (ex.: JogoPerigoso), que sobreescrevia os métodos de criação, mas não o

método montaLabirinto().

– Com isso a estrutura do labirinto permanecia

idêntica, mas os elementos criados pelos métodos de criação eram modificados.

(17)

Classe Jogo

public class Jogo {

// Factory Methods com default

public Labirinto criaLabirinto() { return new Labirinto();

}

public Sala criaSala(int númeroDaSala) { return new Sala(númeroDaSala);

}

public Parede criaParede() { return new Parede();

}

public Porta criaPorta(Sala sala1, Sala sala2) { return new Porta(sala1, sala2);

} ...

(18)

Classe Jogo

...

public Labirinto montaLabirinto() {

Labirinto umLabirinto = criaLabirinto(); Sala sala1 = criaSala(1);

Sala sala2 = criaSala(2);

Porta aporta = criaPorta(sala1, sala2); sala1.setVizinho(NORTE, criaParede()); sala1.setVizinho(LESTE, aporta); sala1.setVizinho(SUL, criaParede()); sala1.setVizinho(OESTE, criaParede()); sala2.setVizinho(NORTE, criaParede()); sala2.setVizinho(LESTE, criaParede()); sala2.setVizinho(SUL, criaParede()); sala2.setVizinho(OESTE, aporta); return umLabirinto; }

(19)

Classe JogoPerigoso

public class JogoPerigoso extends Jogo { public Parede criaParede() {

return new ParedeDestrutível(); }

public Sala criaSala(int númeroDaSala) { return new SalaComBomba(númeroDaSala); }

(20)

Abstract Factory

• Mas e se fizéssemos de outra forma?

• E se separássemos mais um pouco a função de

criar objetos?

(21)

Classe Jogo

public Labirinto montaLabirinto() {

Labirinto umLabirinto = criaLabirinto(); Sala sala1 = criaSala(1);

Sala sala2 = criaSala(2);

Porta aporta = criaPorta(sala1, sala2); sala1.setVizinho(NORTE, criaParede()); sala1.setVizinho(LESTE, aporta); sala1.setVizinho(SUL, criaParede()); sala1.setVizinho(OESTE, criaParede()); sala2.setVizinho(NORTE, criaParede()); sala2.setVizinho(LESTE, criaParede()); sala2.setVizinho(SUL, criaParede()); sala2.setVizinho(OESTE, aporta); return umLabirinto; }

(22)

Classe Jogo (Abstract Factory)

public LabirintoIF montaLabirinto(FactoryDeLabirintoIF factory) { LabirintoIF umLabirinto = factory.criaLabirinto();

SalaIF sala1 = factory.criaSala(1); SalaIF sala2 = factory.criaSala(2);

PortaIF aPorta = factory.criaPorta(sala1, sala2); sala1.setVizinho(NORTE, factory.criaParede()); sala1.setVizinho(LESTE, aPorta);

sala1.setVizinho(SUL, factory.criaParede()); sala1.setVizinho(OESTE, factory.criaParede()); sala2.setVizinho(NORTE, factory.criaParede()); sala2.setVizinho(LESTE, factory.criaParede()); sala2.setVizinho(SUL, factory.criaParede()); sala2.setVizinho(OESTE, aPorta);

return umLabirinto; }

(23)

Abstract Factory

(24)

Abstract Factory

• Padrão semelhante ao Factory Method, mas

– Em vez do cliente (que quer criar objetos sem saber as classes exatas) chamar um método de criação (Factory Method), ele de alguma forma possui um objeto (uma Abstract Factory) e usa este objeto para chamar os

métodos de criação

– Onde Factory Method quer que você seja diferente (via herança) para criar objetos diferentes, o Abstract Factory quer que você tenha algo diferente

(25)

Abstract Factory

• Se ele possuir uma referência a uma Abstract

Factory diferente, toda a criação será

diferente

• O fato de todos os métodos de criação

estarem na mesma subclasse de uma Abstract

Factory permite satisfazer a restrição de criar

apenas objetos relacionados ou dependentes

(26)

Abstract Factory

• Ou seja... ao invés da classe “Jogo” ter que ser

estendida para implementar os factory

methods, eu apenas passo uma “Factory”.

• E aí? Interessante?

• Note que a partir de agora, as factories que

vão ser implementadas / estendidas.

(27)

Classe FactoryDeLabirinto

public class FactoryDeLabirinto implements FactoryDeLabirintoIF { // Factory Methods

// Tem default para as Factory Methods public LabirintoIF criaLabirinto() { return new Labirinto();

}

public SalaIF criaSala(int númeroDaSala) { return new Sala(númeroDaSala);

}

public ParedeIF criaParede() { return new Parede();

}

public PortaIF criaPorta(SalaIF sala1, SalaIF sala2) { return new Porta(sala1, sala2);

(28)

Classe FactoryDeLabirintoPerigoso

public class FactoryDeLabirintoPerigoso extends FactoryDeLabirinto { public SalaIF criaSala(int númeroDaSala) {

return new SalaComBomba(númeroDaSala); }

public ParedeIF criaParede() { return new ParedeDestrutível(); }

}

JogoIF umJogo = new Jogo();

FactoryDeLabirinto factory = new FactoryDeLabirintoPerigoso(); jogo.montaLabirinto(factory);

(29)

Abstract Factory

• Observe que podemos ir um pouco além.

• Podemos introduzir o padrão Singleton, bem

como deixar a classe FactoryDeLabirinto

responsável por instanciar as factories.

– Tem como vantagem tirar do usuário a utilização das subclasses, uma vez que ele está interessado apenas na interface.

(30)

Classe FactoryDeLabirintoPerigoso

public class FactoryDeLabirinto implements FactoryDeLabirintoIF { private static FactoryDeLabirintoIF instânciaÚnica = null;

private FactoryDeLabirinto() {}

public static FactoryDeLabirintoIF getInstance(String tipo) { if(instânciaÚnica == null) {

if(tipo.equals("perigoso")) {

instânciaÚnica = new FactoryDeLabirintoPerigoso(); } else if(tipo.equals("encantado")) {

instânciaÚnica = new FactoryDeLabirintoEncantado(); } else {

instânciaÚnica = new FactoryDeLabirinto(); }

}

return instânciaÚnica; }

(31)

Abstract Factory

• Ao invés do usuário instanciar conhecendo as

subclasses ele passa a criar assim:

JogoIF umJogo = new Jogo();

FactoryDeLabirinto factory = new FactoryDeLabirinto(“perigoso”);

(32)

Abstract Factory

• Objetivo

– Prover uma interface para criar uma família de objetos relacionados ou dependentes sem

especificar suas classes concretas

• Também chamado de

(33)
(34)

Exemplo: look-and-feel de GUIs

• Para look-and-feel diferentes (Motif, Windows, Mac,

Presentation Manager, etc.) temos formas diferentes de manipular janelas, scroll bars, menus, etc.

• Para criar uma aplicação com GUI que suporte qualquer look-and-feel, precisamos ter uma forma simples de criar objetos (relacionados) de uma mesma família

• Os objetos são dependentes porque não posso criar uma janela estilo Windows e um menu estilo Motif

• Java já resolveu este problema internamente no package awt usando Abstract Factory e você não precisa se preocupar com isso

– Porém, você poderia estar usando C++ e precisaria cuidar disso você mesmo

(35)

Exemplo: look-and-feel de GUIs

• Uma classe (abstrata) (ou interface, em Java)

"Abstract Factory" define uma interface para criar cada tipo de objeto básico (widgets no linguajar GUI) • Também tem uma classe abstrata para cada tipo de

widget (window, scroll bar, menu, ...)

• Há classes concretas para implementar cada widget em cada plataforma (look-and-feel)

• Clientes chamam a Abstract Factory para criar objetos

(36)
(37)

Exemplo: look-and-feel de GUIs

• Perceba o que o cliente precisa conhecer apenas:

– A interface da fábrica (WidgetFactoryIF)

– A interface de cada widget (WindowIF, ScrollBarIF)

• Em Java costumamos fazer isso:

public static void main(String args[]) {

try {

UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) {

System.out.println("Nimbus isn't available"); }

TelaVaquinha vaquinhaGUI = new TelaVaquinha(); vaquinhaGUI.setVisible(true);

(38)

O padrão Abstract Factory

• Quando usar o padrão 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

(39)
(40)

Participantes

• FactoryIF (WidgetFactoryIF)

– Define uma interface para as operações que criam objetos como produtos abstratos

• FactoryAbstrata (WidgetFactory)

– Possível classe abstrata para fatorar o código comum às FactoryConcretas

• FactoryConcreta (MotifWidgetFactory, WindowsWidgetFactory)

– Implementa as operações para criar objetos para produtos concretos

• ProdutoXIF (WindowIF, ScrollBarIF)

– Define uma interface para objetos de um tipo

• ProdutoAbstrato (Window, ScrollBar)

– Possível classe abstrata para fatorar o código comum aos ProdutosConcretos

• ProdutoConcreto (MotifWindow, MotifScrollBar)

– Define um objeto produto a ser criado pela FactoryConcreta correspondente – Implementa a interface de ProdutoAbstrato

• Cliente

(41)

Colaborações entre objetos

• Normalmente uma única instância de uma classe FactoryConcreta é criada em tempo de execução • Essa FactoryConcreta cria objetos tendo uma

implementação particular

• Para criar produtos diferentes, clientes devem usar uma FactoryConcreta diferente

• FactoryAbstrata depende de suas subclasses FactoryConcreta para criar objetos de produtos

(42)

Consequências do uso do padrão Abstract Factory

• O padrão isola classes concretas

– Uma factory encapsula a responsabilidade e o processo de criação de objetos de produtos

– Isola clientes das classes de implementação

– O cliente manipula instâncias através de suas interfaces abstratas

(43)

Consequências do uso do padrão Abstract Factory

• Facilita o câmbio de famílias de produtos

– A classe da FactoryConcreta só aparece em um lugar: onde ela é instanciada

– Uma mudança numa única linha de código pode ser

suficiente para mudar a FactoryConcreta que a aplicação usa

(44)

Consequências do uso do padrão Abstract Factory

• Promove a consistência entre produtos

– Produtos de uma determinada família devem funcionar conjuntamente e não misturados com produtos de outra família

– O padrão permite implementar esta restrição com facilidade

(45)

Consequências do uso do padrão Abstract Factory

• Do lado negativo: dar suporte a novos tipos de produtos é difícil

– O motivo é que a FactoryAbstrata fixa o conjunto de produtos que podem ser criados

– Dar suporte a mais produtos força a extensão da interface da factory o que envolve mudanças na FactoryAbstrata e em todas suas subclasses FactoryConcreta

(46)

Considerações de implementação

• Factory como padrão Singleton

– Uma aplicação normalmente só precisa de uma única

instância de uma FactoryConcreta por família de produtos – O padrão Singleton ajuda a controlar a instância única

• Criação dos produtos

– A FactoryIF apenas define a interface de criação – Quem cria os objetos são as FactoryConcreta

• Tais subclasses são freqüentemente implementadas usando o padrão Factory Method

• Uma FactoryConcreta faz override do Factory Method de cada produto

(47)

PADRÕES DE CRIAÇÃO

(48)

Discussão geral de padrões de criação

• Ajudam a deixar o sistema independente de como seus objetos são criados, compostos e representados • São dois tipos:

– Padrões de criação via classes

• Usam herança para variar a classe que é instanciada • Exemplo: Factory Method

– Padrões de criação via objetos

• Delegam a instanciação para outro objeto • Exemplo: Abstract Factory

(49)

Discussão geral de padrões de criação

• Composição é usada mais que herança para estender funcionalidade e padrões de criação ajudam a lidar com a complexidade de criar comportamentos

– Em vez de codificar um comportamento estaticamente, definimos pequenos comportamentos padrão e usamos composição para definir comportamentos mais complexos

– Isso significa que instanciar um objeto com um comportamento particular requer mais do que simplesmente instanciar uma

classe

– Eles escondem como instâncias das classes concretas são

criadas e juntadas para gerar "comportamentos" (que podem envolver vários objetos compostos)

– Os padrões mostrados aqui mostram como encapsular as coisas de forma a simplificar o problema de instanciação

(50)

Discussão geral de padrões de criação

• Os padrões de criação discutem temas recorrentes:

– Eles encapsulam o conhecimento das classes concretas que são instanciadas

• Lembre que preferimos nos "amarrar" a interfaces (via interface ou classes abstratas) do que a classes concretas

• Isso promove a flexibilidade de mudança (das classes concretas que são instanciadas)

(51)

Perguntas finais para discussão

• Na seção de implementação deste padrão, os autores (Gamma et al.) discutem a idéia de definir factories

extensíveis. Já que uma Abstract Factory consiste de

Factory Methods e que cada Factory Method tem apenas uma assinatura, isto significa que o Factory Method só pode criar um objeto de uma única

(52)

Perguntas finais para discussão

• Considere o exemplo de construção de labirintos. O FactoryDeLabirinto contém um método criaSala() que recebe um inteiro como parâmetro,

representando o número da sala. O que acontece se você também quer especificar o tamanho e cor da sala? Isto significa que você deveria criar um novo Factory Method para o FactoryDeLabirinto,

permitindo passar como parâmetros o número da sala, tamanho e cor para um outro método

(53)

Perguntas finais para discussão

• Claro que nada impediria que alterasse a cor e

tamanho da sala depois que tiver sido instanciada, mas isso deixaria o código mais "cheio e sujo",

especialmente se você estiver criando e

configurando muitos objetos. Como reter o FactoryDeLabirinto e usar apenas um método

criaSala() e acomodar diferentes parâmetros usados por criaSala() para criar e configurar objetos do tipo Sala?

(54)

Perguntas finais para discussão

• No exemplo (FactoryDeLabirinto), não há estado a ser mantido na instância única do singleton. Você

acha que um singleton é realmente necessário aqui? O que ocorreria se permitissemos a criação de mais de uma instância?

• No exemplo (FactoryDeLabirinto), o que ocorre se getInstance("...") for chamado mais de uma vez com parâmetros diferentes?

Referências

Documentos relacionados

n A classe Abstract Factory especifica quais objetos podem ser instanciados definindo um método para cada um desses tipos diferentes de objetos. diferentes

Esta dissertação aborda o uso de atividades de robótica como recurso tecnológico para a exploração de conceitos relacionados à transferência de calor no ensino

Bridge Command Chain of Responsibility Abstract Factory Prototype Template Method Factory Method Observer Mediator Strategy Decorator Flyweight Composite Interpreter Visitor

Creational Abstract Factory Builder Factory Method Prototype Singleton Structural Adapter Bridge Composite Decorator Facade Flyweight • Proxy Behavioral Chain

Este trabalho busca discutir uma tendência dos últimos tempos: a utilização de filmes cinematográficos como um meio alternativo para a inserção, divulgação e reforço das

Expressão dos receptores das interleucinas de cadeia gama comum em linfócitos T periféricos em pacientes portadores de diabetes mellitus tipo 1 com início recente / Lindiane

Após essa fase foi realizada uma revisão da literatura e um mapeamento de um framework de processo de aquisição com práticas ágeis, para fornecer o

A f´ abrica de ingredientes agora ´e usada para produzir pizzas O tipo de ingrediente depende do tipo de f´ abrica usada Se usarmos uma f´ abrica de ingredientes de S˜ ao Luis,