1. O documento descreve o padrão de projeto Factory Method, no qual uma classe abstrata declara um método de fábrica para criar objetos, permitindo que subclasses especifiquem o tipo de objetos criados. 2. O método de fábrica separa a lógica de criação de objetos do código cliente, permitindo variações na criação de objetos sem alterar o código cliente. 3. O exemplo mostra como o Factory Method pode ser usado para criar elementos de interface de usuário de forma independente da plataforma, com subclasses retornando elementos espec
1. 1. A produtos declara a interface, que é comum a todos1. A produtos declara a interface, que é comum a todos1. A produtos declara a interface, que é comum a todos
objetos que podem ser produzidos pelo criador e suas subclasses.
2. produtos de concreto são diferentes implementações da produ-2. produtos de concreto são diferentes implementações da produ-2. produtos de concreto são diferentes implementações da produ-
interface de UCT.
3. A O Criador classe declara o método de fábrica que retorna3. A O Criador classe declara o método de fábrica que retorna3. A O Criador classe declara o método de fábrica que retorna
novos objetos produtos. É importante que o tipo de retorno desse método coincide
com a interface do produto.
Você pode declarar o método de fábrica como abstrata para forçar todas as subclasses
para implementar as suas próprias versões do método. Como alternativa, o método de
fábrica base pode retornar algum tipo de produto padrão.
Note, apesar do seu nome, a criação do produto é não a responsabilidade primária doNote, apesar do seu nome, a criação do produto é não a responsabilidade primária doNote, apesar do seu nome, a criação do produto é não a responsabilidade primária do
criador. Normalmente, a classe criador já tem alguma lógica do núcleo de negócios
relacionados aos produtos. O método de fábrica contribui para dissociar essa lógica das
classes de produtos concretos. Aqui está uma analogia: uma grande empresa de
desenvolvimento de software pode ter um departamento de formação para
programadores. No entanto, a função principal da empresa como um todo ainda está
escrevendo código, não produzindo programadores.
4. Criadores de concreto substituir o método fábrica de base para que ele4. Criadores de concreto substituir o método fábrica de base para que ele4. Criadores de concreto substituir o método fábrica de base para que ele
retorna um tipo diferente de produto.
76 Criacionais Design Patterns / método de fábrica
2. Note-se que o método de fábrica não tem de crio novas instâncias o tempo todo. EleNote-se que o método de fábrica não tem de crio novas instâncias o tempo todo. EleNote-se que o método de fábrica não tem de crio novas instâncias o tempo todo. Ele
também pode retornar objetos existentes a partir de um cache, um conjunto de objetos,
ou outra fonte.
Pseudo-código
Este exemplo ilustra como o Factory Method pode ser usado para criar elementos deEste exemplo ilustra como o Factory Method pode ser usado para criar elementos deEste exemplo ilustra como o Factory Method pode ser usado para criar elementos de
interface multi-plataforma, sem o acoplamento do código de cliente para as classes de UI
concretas.
A classe de diálogo base utiliza diferentes elementos da interface para tornar a sua janela.
Sob vários sistemas operacionais, esses elementos podem parecer um pouco diferente, mas
eles ainda devem se comportar de forma consistente. Um botão no Windows ainda é um
botão no Linux.
O exemplo de diálogo entre plataformas.
•
77 Criacionais Design Patterns / método de fábrica
3. Quando o método de fábrica entra em jogo, você não precisa reescrever a lógica
do diálogo para cada sistema operacional. Se nós declaramos um método de
fábrica que produz botões dentro da classe de diálogo base, podemos depois
criar uma subclasse de diálogo que retorna botões do Windows-estilo do método
de fábrica. A subclasse então herda a maioria do código do diálogo da classe
base, mas, graças ao método de fábrica, pode render Windowslooking botões na
tela.
Para este padrão para o trabalho, a classe de diálogo base deve trabalhar com botões
abstratos: uma classe base ou uma interface que todos os botões de concreto seguir. Desta
forma, o código do diálogo permanece funcional, qualquer tipo de botões que trabalha com.
Claro, você pode aplicar esta abordagem a outros elementos de interface do usuário também. No
entanto, com cada novo método de fábrica que você adicionar ao diálogo, você se aproximar da Abstractentanto, com cada novo método de fábrica que você adicionar ao diálogo, você se aproximar da Abstract
Factory padronizar. Não temas, vamos falar sobre esse padrão mais tarde.Factory padronizar. Não temas, vamos falar sobre esse padrão mais tarde.
// A classe criador declara o método de fábrica que devem1
// retorna um objeto de uma classe de produto. subclasses do criador2
// geralmente fornecer a implementação deste método.3
classe Diálogo éclasse Diálogo éclasse Diálogo é4
// O criador também pode fornecer algum implementação padrão5
// do método de fábrica.6
método abstrato CreateButton ()método abstrato CreateButton ()método abstrato CreateButton ()7
8
// Note-se que, apesar do nome, primário do criador9
// responsabilidade não é a criação de produtos. ele geralmente10
78 Criacionais Design Patterns / método de fábrica
4. // contém alguma lógica core business que se baseia em produtos11
// objetos retornados pelo método de fábrica. subclasses podem12
// alterar indiretamente que a lógica de negócios, substituindo o13
// método de fábrica e retornando um tipo diferente de produto14
// a partir dele.15
método render () émétodo render () émétodo render () émétodo render () é16
// Chamar o método de fábrica para criar um objeto de produto.17
Botão OKButton = CreateButton ()18
// Agora usar o produto.19
okButton.onClick ( CloseDialog )okButton.onClick ( CloseDialog )okButton.onClick ( CloseDialog )okButton.onClick ( CloseDialog )20
okButton.render ()okButton.render ()21
22
23
// criadores de concreto substituir o método fábrica para mudar o24
// resultando tipo de produto.25
classe WindowsDialog estende Diálogo éclasse WindowsDialog estende Diálogo éclasse WindowsDialog estende Diálogo éclasse WindowsDialog estende Diálogo éclasse WindowsDialog estende Diálogo é26
método CreateButton () émétodo CreateButton () émétodo CreateButton () émétodo CreateButton () é27
retornar nova WindowsButton ()retornar nova WindowsButton ()retornar nova WindowsButton ()28
29
classe WebDialog estende Diálogo éclasse WebDialog estende Diálogo éclasse WebDialog estende Diálogo éclasse WebDialog estende Diálogo éclasse WebDialog estende Diálogo é30
método CreateButton () émétodo CreateButton () émétodo CreateButton () émétodo CreateButton () é31
retornar nova HtmlButton ()retornar nova HtmlButton ()retornar nova HtmlButton ()32
33
34
// A interface do produto declara as operações que todos os35
// Produtos de concreto deve implementar.36
interface Botão éinterface Botão éinterface Botão é37
método render ()método render ()método render ()38
método onClick ( f )método onClick ( f )método onClick ( f )método onClick ( f )método onClick ( f )39
40
// Produtos em betão fornecer várias implementações do41
// interface do produto.42
79 Criacionais Design Patterns / método de fábrica
5. classe WindowsButton implementos Botão éclasse WindowsButton implementos Botão éclasse WindowsButton implementos Botão éclasse WindowsButton implementos Botão éclasse WindowsButton implementos Botão é43
método render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) é44
// rende um botão no estilo do Windows.45
método onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) é46
// Vincular um evento OS clique nativa.47
48
classe HtmlButton implementos Botão éclasse HtmlButton implementos Botão éclasse HtmlButton implementos Botão éclasse HtmlButton implementos Botão éclasse HtmlButton implementos Botão é49
método render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) émétodo render ( a, b ) é50
// Retorna uma representação em HTML de um botão.51
método onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) émétodo onClick ( f ) é52
// Vincular um evento web navegador clique.53
54
55
classe Aplicação éclasse Aplicação éclasse Aplicação é56
campo diálogo : Dialogcampo diálogo : Dialogcampo diálogo : Dialog57
58
// O aplicativo escolhe o tipo de um criador, dependendo do59
// definições de configuração ou ambiente atual.60
método inicializar () émétodo inicializar () émétodo inicializar () émétodo inicializar () é61
config = readApplicationConfigFile ()config = readApplicationConfigFile ()62
63
E se ( config.OS == "Janelas" ) entãoE se ( config.OS == "Janelas" ) entãoE se ( config.OS == "Janelas" ) entãoE se ( config.OS == "Janelas" ) entãoE se ( config.OS == "Janelas" ) entãoE se ( config.OS == "Janelas" ) então64
diálogo = Novo WindowsDialog ()diálogo = Novo WindowsDialog ()diálogo = Novo WindowsDialog ()diálogo = Novo WindowsDialog ()65
else if ( config.OS == "Rede" ) entãoelse if ( config.OS == "Rede" ) entãoelse if ( config.OS == "Rede" ) entãoelse if ( config.OS == "Rede" ) entãoelse if ( config.OS == "Rede" ) entãoelse if ( config.OS == "Rede" ) então66
diálogo = Novo WebDialog ()diálogo = Novo WebDialog ()diálogo = Novo WebDialog ()diálogo = Novo WebDialog ()67
outro68
throw new Exceção ( "Erro! Sistema operacional desconhecido". )throw new Exceção ( "Erro! Sistema operacional desconhecido". )throw new Exceção ( "Erro! Sistema operacional desconhecido". )throw new Exceção ( "Erro! Sistema operacional desconhecido". )throw new Exceção ( "Erro! Sistema operacional desconhecido". )69
70
// O código do cliente trabalha com uma instância de um concreto71
// criador, ainda que por meio de sua interface base. Enquanto72
// o cliente mantém a trabalhar com o criador através da base73
// interface, você pode passá-lo subclasse qualquer criador.74
80 Criacionais Design Patterns / método de fábrica
6. aplicabilidade
Use o Factory Method quando você não sabe de antemão os tipos exatos e
dependências dos objectos seu código deve trabalhar.
O Factory Method separa código de construção do produto do código que
realmente usa o produto. Portanto, é mais fácil estender o código de construção
do produto de forma independente do resto do código.
Por exemplo, para adicionar um novo tipo de produto para o aplicativo, você só precisa
criar uma nova subclasse criador e substituir o método de fábrica nele.
Use o método de fábrica quando pretende fornecer aos usuários de sua biblioteca ou
quadro com uma maneira de estender seus componentes internos.
A herança é provavelmente a maneira mais fácil de estender o comportamento
padrão de uma biblioteca ou quadro. Mas como é que o quadro reconhecem que sua
subclasse deve ser usado em vez de um componente padrão?
método a Principal () émétodo a Principal () émétodo a Principal () émétodo a Principal () é75
isto . inicializar ()isto . inicializar ()isto . inicializar ()isto . inicializar ()76
dialog.render ()dialog.render ()77
•
•
•
•
•
81 Criacionais Design Patterns / método de fábrica
7. A solução é reduzir o código que constrói componentes em todo o quadro
em um único método de fábrica e deixar qualquer um substituir esse
método, além de aumentar o próprio componente.
Vamos ver como isso funciona. Imagine que você escrever um aplicativo
usando um quadro UI de código aberto. Seu aplicativo deve ter botões
redondos, mas o quadro só fornece os quadrados. Você estender o padrão Botãoredondos, mas o quadro só fornece os quadrados. Você estender o padrão Botão
classe com uma gloriosa
RoundButton subclasse. Mas agora você tem de dizer o principalRoundButton subclasse. Mas agora você tem de dizer o principal
UIFramework classe para usar a nova subclasse botão em vez de um padrão.UIFramework classe para usar a nova subclasse botão em vez de um padrão.
Para conseguir isso, você criar uma subclasse UIWithRoundButtonsPara conseguir isso, você criar uma subclasse UIWithRoundButtons
de uma classe estrutura de base e substituir seu CreateButtonde uma classe estrutura de base e substituir seu CreateButton
método. Enquanto este método retorna Botão objetos na classe base, você fazmétodo. Enquanto este método retorna Botão objetos na classe base, você fazmétodo. Enquanto este método retorna Botão objetos na classe base, você faz
o seu retorno subclasse RoundButton objetos. Agora use oo seu retorno subclasse RoundButton objetos. Agora use oo seu retorno subclasse RoundButton objetos. Agora use o
UIWithRoundButtons classe ao invés de
UIFramework. E é sobre isso!UIFramework. E é sobre isso!
Use o Factory Method quando você quiser economizar recursos do sistema através da
reutilização de objetos existentes em vez de reconstruí-los cada vez.
Você muitas vezes experimentam esta necessidade quando se lida com objetos grandes que
consomem muitos recursos, como conexões de banco de dados, sistemas de arquivos e recursos
de rede.
•
•
82 Criacionais Design Patterns / método de fábrica
8. Vamos pensar sobre o que tem de ser feito para reutilizar um objeto existente:
1. Primeiro, você precisa criar algum tipo de armazenamento para manter o controle de todos os
objetos criados.
2. Quando alguém solicita um objeto, o programa deve procurar um objeto livre
dentro dessa piscina.
3. ... e, em seguida, devolvê-lo para o código do cliente.
4. Se não existirem objectos livres, o programa deve criar um novo (e
adicioná-lo à piscina).
Isso é um monte de código! E tudo deve ser colocado em um único lugar para que você
não poluem o programa com código duplicado.
Provavelmente o lugar mais óbvio e conveniente onde este código pode ser
colocado é o construtor da classe cujos objetos que estamos tentando reutilizar. No
entanto, um construtor deve sempre retornar novos objetos por definição. Ele nãoentanto, um construtor deve sempre retornar novos objetos por definição. Ele nãoentanto, um construtor deve sempre retornar novos objetos por definição. Ele não
pode retornar instâncias existentes.
Portanto, você precisa ter um método regular capaz de criar novos objetos,
bem como reutilizar os já existentes. Isso soa muito parecido com um método
de fábrica.
Como implementar
1. Faça todos os produtos seguem a mesma interface. Esta interface deve declarar
métodos que fazem sentido em todos os produtos.
•
83 Criacionais Design Patterns / método de fábrica
9. 2. Adicionar um método de fábrica vazia dentro da classe criador. O tipo de retorno
do método deve corresponder à interface comum produto.
3. No código do criador encontrar todas as referências a construtores de produtos. Um
por um, substituí-los com chamadas para o método de fábrica, ao extrair o código de
criação do produto para o método de fábrica.
Talvez seja necessário adicionar um parâmetro temporário para o método de fábrica para
controlar o tipo de produto devolvido.
Neste ponto, o código do método de fábrica pode parecer muito feio. Ele pode ter um
grande interruptor operador que pega que classe de produto para instanciar. Mas não segrande interruptor operador que pega que classe de produto para instanciar. Mas não segrande interruptor operador que pega que classe de produto para instanciar. Mas não se
preocupe, nós vamos corrigi-lo em breve.
4. Agora, criar um conjunto de subclasses Criador para cada tipo de produto listada no
método de fábrica. Substituir o método fábrica nas subclasses e extrair os
pedaços apropriados de código de construção a partir do método de base.
5. Se houver muitos tipos de produtos e não faz sentido criar subclasses para
todos eles, você pode reutilizar o parâmetro de controle da classe base em
subclasses.
Por exemplo, imagine que você tem a seguinte hierarquia de classes: a
base Enviar classe com um par de subclasses:base Enviar classe com um par de subclasses:base Enviar classe com um par de subclasses:
Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,Correio aéreo e GroundMail; a Transporte classes são Avião ,
84 Criacionais Design Patterns / método de fábrica
10. Caminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas AviãoCaminhão e Trem . Enquanto o Correio aéreo classe usa apenas Avião
objetos, GroundMail pode trabalhar com ambos Caminhão e Tremobjetos, GroundMail pode trabalhar com ambos Caminhão e Tremobjetos, GroundMail pode trabalhar com ambos Caminhão e Tremobjetos, GroundMail pode trabalhar com ambos Caminhão e Tremobjetos, GroundMail pode trabalhar com ambos Caminhão e Tremobjetos, GroundMail pode trabalhar com ambos Caminhão e Trem
objetos. Você pode criar uma nova subclasse (digamos TrainMail) para lidar comobjetos. Você pode criar uma nova subclasse (digamos TrainMail) para lidar comobjetos. Você pode criar uma nova subclasse (digamos TrainMail) para lidar com
ambos os casos, mas não há outra opção. O código do cliente pode passar um
argumento para o método de fábrica do
GroundMail classe para controlar qual o produto que ele quer receber.GroundMail classe para controlar qual o produto que ele quer receber.
6. Se, depois de todas as extrações, o método de fábrica de base tornou-se vazio,
você pode torná-lo abstrata. Se há algo à esquerda, você pode torná-lo um
comportamento padrão do método.
Prós e contras
Você evitar acoplamento forte entre o criador e os produtos concretos.
Princípio da responsabilidade única. Você pode mover o código de criação do produtoPrincípio da responsabilidade única. Você pode mover o código de criação do produto
em um lugar no programa, tornando o código mais fácil de suportar.
Abrir / Princípio fechado. Você pode introduzir novos tipos de produtos no programaAbrir / Princípio fechado. Você pode introduzir novos tipos de produtos no programa
sem quebrar o código do cliente existente.
O código pode se tornar mais complicado desde que você precisa para introduzir
uma série de novas subclasses para implementar o padrão. O melhor cenário é
quando você está introduzindo o padrão em uma hierarquia existente das classes
criador.
•
•
•
•
•
85 Criacionais Design Patterns / método de fábrica
11. Relações com outros padrões de
• Muitos projetos comece usando Factory Method ( menos complicado e maisMuitos projetos comece usando Factory Method ( menos complicado e maisMuitos projetos comece usando Factory Method ( menos complicado e mais
personalizável através de subclasses) e evoluir na direção
Abstract Factory, Protótipo, ou Builder ( mais flexível, mas mais complicado).Abstract Factory, Protótipo, ou Builder ( mais flexível, mas mais complicado).Abstract Factory, Protótipo, ou Builder ( mais flexível, mas mais complicado).Abstract Factory, Protótipo, ou Builder ( mais flexível, mas mais complicado).Abstract Factory, Protótipo, ou Builder ( mais flexível, mas mais complicado).
• Abstract Factory aulas são muitas vezes baseadas em um conjunto de Métodos de fábrica, masAbstract Factory aulas são muitas vezes baseadas em um conjunto de Métodos de fábrica, masAbstract Factory aulas são muitas vezes baseadas em um conjunto de Métodos de fábrica, masAbstract Factory aulas são muitas vezes baseadas em um conjunto de Métodos de fábrica, mas
você também pode usar Protótipo para compor os métodos sobre essas classes.você também pode usar Protótipo para compor os métodos sobre essas classes.você também pode usar Protótipo para compor os métodos sobre essas classes.
• Você pode usar Factory Method junto com iterator para permitir que subclasses deVocê pode usar Factory Method junto com iterator para permitir que subclasses deVocê pode usar Factory Method junto com iterator para permitir que subclasses deVocê pode usar Factory Method junto com iterator para permitir que subclasses deVocê pode usar Factory Method junto com iterator para permitir que subclasses de
recolha de retornar diferentes tipos de iteradores que são compatíveis com as coleções.
• Protótipo não se baseia em herança, por isso não tem suas desvantagens.Protótipo não se baseia em herança, por isso não tem suas desvantagens.
Por outro lado, Protótipo requer uma complicada inicialização do objectoPor outro lado, Protótipo requer uma complicada inicialização do objectoPor outro lado, Protótipo requer uma complicada inicialização do objecto
clonado. Factory Method é baseada na herança, mas não requer uma etapaclonado. Factory Method é baseada na herança, mas não requer uma etapaclonado. Factory Method é baseada na herança, mas não requer uma etapa
de inicialização.
• Factory Method é uma especialização de Template Method. Ao mesmo tempo, a FactoryFactory Method é uma especialização de Template Method. Ao mesmo tempo, a FactoryFactory Method é uma especialização de Template Method. Ao mesmo tempo, a FactoryFactory Method é uma especialização de Template Method. Ao mesmo tempo, a FactoryFactory Method é uma especialização de Template Method. Ao mesmo tempo, a Factory
Method pode servir como um passo numa grande Template Method.Method pode servir como um passo numa grande Template Method.Method pode servir como um passo numa grande Template Method.
•
86 Criacionais Design Patterns / método de fábrica