Padrão Factory
Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 55 de 61.
O padrão Factory centraliza a criação de objetos em uma única função. Em vez de espalhar o malloc e o código de inicialização por todo o seu programa, você chama uma função que decide o que criar e retorna um objeto pronto para uso.
Este padrão é especialmente poderoso quando combinado com polimorfismo. Uma factory pode retornar diferentes tipos concretos através de um ponteiro base comum, ocultando os detalhes de criação de quem faz a chamada. Quem faz a chamada apenas solicita "uma forma" e a factory decide se deve construir um círculo, retângulo ou outra coisa.
Aqui está uma implementação típica de factory:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}A fábrica recebe um identificador (geralmente um enum) e usa uma instrução switch para determinar qual construtor chamar. Ela retorna um Shape* independentemente do tipo real criado. O chamador não precisa saber sobre Circle ou Rectangle — ele apenas trabalha com o tipo base:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // chamada polimórfica
free_shape(s);Este padrão torna a adição de novos tipos fácil: basta adicionar um novo valor de enum e um novo caso na factory. O restante do seu código permanece inalterado.
Desafio
FácilVamos construir uma Pet Factory — um sistema que cria diferentes tipos de animais de estimação por meio de uma única função de fábrica. Em vez de espalhar a lógica de criação por todo o seu código, você a centralizará em um único lugar que decide que tipo de pet criar com base em um identificador de entrada.
Você organizará seu código em três arquivos:
pet.h: Defina um enumPetTypecom os valoresPET_DOG,PET_CATePET_BIRD. Crie uma struct basePetque contenha um ponteiro de função paraspeak(que recebe umconst Pet*e não retorna nada). Declare a função de fábricacreate_petque recebe umPetTypee retorna umPet*, além de uma funçãofree_petpara limpeza.pet.c: Defina três structs de pets concretas —Dog,CateBird— cada uma incorporandoPetcomo seu primeiro membro. Implemente uma função speak para cada tipo:- Cães imprimem:
Woof! - Gatos imprimem:
Meow! - Pássaros imprimem:
Tweet!
create_pet— use uma instrução switch noPetTypepara chamar o construtor correto e retornar o resultado como umPet*. Para tipos inválidos, retorneNULL. Implementefree_petpara liberar a memória alocada.- Cães imprimem:
main.c: Leia um número inteiro representando o tipo de pet (0 para cão, 1 para gato, 2 para pássaro). Use sua fábrica para criar o pet apropriado, chame sua funçãospeakpolimorficamente através do ponteiro basePet*e, em seguida, libere o pet.
Seu programa receberá uma entrada: um número inteiro indicando qual pet criar.
Exemplo de saída quando a entrada é 0:
Woof!Exemplo de saída quando a entrada é 1:
Meow!Exemplo de saída quando a entrada é 2:
Tweet!A beleza do padrão Factory é que o main.c não precisa saber sobre as structs Dog, Cat ou Bird — ele trabalha apenas com o tipo base Pet. Adicionar um novo tipo de pet posteriormente significa adicionar um novo valor ao enum e um novo caso na fábrica, sem alterar nenhum código que utilize os pets.
Folha de consulta
O padrão Factory centraliza a criação de objetos em uma única função, escondendo os detalhes de criação de quem a chama.
Uma função factory recebe um identificador (geralmente um enum) e usa uma instrução switch para determinar qual construtor chamar, retornando um ponteiro de tipo base:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}O chamador trabalha apenas com o tipo base, permitindo comportamento polimórfico:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // polymorphic call
free_shape(s);Benefícios: Adicionar novos tipos requer apenas a adição de um novo valor de enum e um caso no switch, sem alterar o código existente que utiliza a factory.
Experimente você mesmo
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: Use a fábrica para criar o pet apropriado
// Hint: Faça o cast do int para PetType
// TODO: Chame a função speak polimorficamente através do ponteiro Pet*
// TODO: Libere o pet
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos da Programação Modular
Arquivos de CabeçalhoInclude GuardsArquivos-FonteFunções EstáticasRecapitulação: Calculadora Modular4Encapsulamento
Conceito de Ponteiros OpacosDefinindo Structs OpacasGetters e SettersValidação em SettersRecapitulação: Caixa Secreta2Objetos e Métodos
Structs como ObjetosO Ponteiro 'Self'Const CorrectnessPonteiro vs ValorMétodos AuxiliaresRecapitulação: Point Manager5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de Vida de Objetos
Padrão de ConstrutorPadrão de DestrutorInicialização na StackCópia ProfundaRecapitulação: String Wrapper6Herança via Composição
Incorporação de StructsA Regra do Primeiro MembroAcessando Membros PaiUpcastingRecapitulação: Hierarquia de Formas9Projeto: Desenhador de Formas
Visão Geral do ProjetoImplementação do Círculo