Abstract Factory
O Abstract Factory é um padrão criacional utilizado para criar famílias de objetos relacionados sem precisar conhecer suas implementações concretas.
Enquanto o Factory Method normalmente se concentra na criação de um tipo de produto, o Abstract Factory trabalha com um conjunto de produtos que precisam ser compatíveis entre si.
Um exemplo clássico é uma interface gráfica.
Podemos ter:
Windows
├── WindowsButton
└── WindowsCheckbox
MacOS
├── MacButton
└── MacCheckbox
Queremos garantir que todos os componentes utilizados pertençam à mesma família.
Interfaces
Criamos os produtos:
interface Button {
render(): void;
}
interface Checkbox {
render(): void;
}
Agora criamos a fábrica:
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
Família Windows
class WindowsButton
implements Button {
render() {
console.log(
"Renderizando botão Windows"
);
}
}
class WindowsCheckbox
implements Checkbox {
render() {
console.log(
"Renderizando checkbox Windows"
);
}
}
A fábrica:
class WindowsFactory
implements GUIFactory {
createButton(): Button {
return new WindowsButton();
}
createCheckbox(): Checkbox {
return new WindowsCheckbox();
}
}
Família MacOS
class MacButton
implements Button {
render() {
console.log(
"Renderizando botão MacOS"
);
}
}
class MacCheckbox
implements Checkbox {
render() {
console.log(
"Renderizando checkbox MacOS"
);
}
}
A fábrica:
class MacFactory
implements GUIFactory {
createButton(): Button {
return new MacButton();
}
createCheckbox(): Checkbox {
return new MacCheckbox();
}
}
Utilizando a fábrica
O código cliente trabalha apenas com interfaces:
function renderUI(
factory: GUIFactory
) {
const button =
factory.createButton();
const checkbox =
factory.createCheckbox();
button.render();
checkbox.render();
}
Podemos escolher a família:
renderUI(
new WindowsFactory()
);
Ou:
renderUI(
new MacFactory()
);
O restante do código não precisa saber quais classes concretas foram criadas.
Quando usar?
O Abstract Factory é útil quando:
- Temos famílias de objetos relacionados.
- Os objetos precisam ser compatíveis entre si.
- Queremos trocar uma família inteira de implementações.
- Queremos evitar misturar produtos incompatíveis.
Por exemplo:
WindowsFactory
├── WindowsButton
└── WindowsCheckbox
Em vez de:
WindowsButton
+
MacCheckbox
A fábrica garante a consistência da família.
Resumo
Abstract Factory
│
├── createButton()
│ ↓
│ Button
│
└── createCheckbox()
↓
Checkbox
A ideia principal é:
Criar famílias de objetos relacionados e compatíveis entre si.