Паттерн Abstract Factory предоставляет интерфейс для создания семейств связанных объектов без указания их конкретных классов. Он помогает создавать взаимосвязанные объекты, сохраняя согласованность между ними и облегчая замену целых семейств продуктов.
Когда применять Abstract Factory
- Когда система должна быть независима от способа создания и представления продуктов.
- Когда требуется создавать семейства связанных объектов.
- Когда необходимо обеспечить совместимость между продуктами внутри одного семейства.
PlantUML-диаграмма
public interface IButton
{
void Paint();
}
public interface ICheckbox
{
void Paint();
}
// Конкретные продукты
public class WinButton : IButton
{
public void Paint() => Console.WriteLine("Рисуем кнопку в стиле Windows.");
}
public class WinCheckbox : ICheckbox
{
public void Paint() => Console.WriteLine("Рисуем чекбокс в стиле Windows.");
}
public class MacButton : IButton
{
public void Paint() => Console.WriteLine("Рисуем кнопку в стиле macOS.");
}
public class MacCheckbox : ICheckbox
{
public void Paint() => Console.WriteLine("Рисуем чекбокс в стиле macOS.");
}
// Абстрактная фабрика
public interface IGUIFactory
{
IButton CreateButton();
ICheckbox CreateCheckbox();
}
// Конкретные фабрики
public class WinFactory : IGUIFactory
{
public IButton CreateButton() => new WinButton();
public ICheckbox CreateCheckbox() => new WinCheckbox();
}
public class MacFactory : IGUIFactory
{
public IButton CreateButton() => new MacButton();
public ICheckbox CreateCheckbox() => new MacCheckbox();
}
// Клиент
class Application
{
private readonly IButton _button;
private readonly ICheckbox _checkbox;
public Application(IGUIFactory factory)
{
_button = factory.CreateButton();
_checkbox = factory.CreateCheckbox();
}
public void Render()
{
_button.Paint();
_checkbox.Paint();
}
}
class Program
{
static void Main()
{
IGUIFactory factory;
// Пример: выбираем фабрику в зависимости от ОС
string os = "Windows";
factory = os == "Windows" ? new WinFactory() : new MacFactory();
var app = new Application(factory);
app.Render();
}
}
type Button interface{ Paint() }
type Checkbox interface{ Paint() }
type WinButton struct{}
func (WinButton) Paint() { fmt.Println("Рисуем кнопку в стиле Windows.") }
type WinCheckbox struct{}
func (WinCheckbox) Paint() { fmt.Println("Рисуем чекбокс в стиле Windows.") }
type MacButton struct{}
func (MacButton) Paint() { fmt.Println("Рисуем кнопку в стиле macOS.") }
type MacCheckbox struct{}
func (MacCheckbox) Paint() { fmt.Println("Рисуем чекбокс в стиле macOS.") }
// Абстрактная фабрика
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}
type WinFactory struct{}
func (WinFactory) CreateButton() Button { return WinButton{} }
func (WinFactory) CreateCheckbox() Checkbox { return WinCheckbox{} }
type MacFactory struct{}
func (MacFactory) CreateButton() Button { return MacButton{} }
func (MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }
type Application struct {
button Button
checkbox Checkbox
}
func NewApplication(f GUIFactory) *Application {
return &Application{button: f.CreateButton(), checkbox: f.CreateCheckbox()}
}
func (a *Application) Render() {
a.button.Paint()
a.checkbox.Paint()
}
func main() {
var factory GUIFactory = WinFactory{}
if os := "Windows"; os != "Windows" {
factory = MacFactory{}
}
NewApplication(factory).Render()
}
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def paint(self) -> None: ...
class Checkbox(ABC):
@abstractmethod
def paint(self) -> None: ...
class WinButton(Button):
def paint(self) -> None:
print("Рисуем кнопку в стиле Windows.")
class WinCheckbox(Checkbox):
def paint(self) -> None:
print("Рисуем чекбокс в стиле Windows.")
class MacButton(Button):
def paint(self) -> None:
print("Рисуем кнопку в стиле macOS.")
class MacCheckbox(Checkbox):
def paint(self) -> None:
print("Рисуем чекбокс в стиле macOS.")
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button: ...
@abstractmethod
def create_checkbox(self) -> Checkbox: ...
class WinFactory(GUIFactory):
def create_button(self) -> Button:
return WinButton()
def create_checkbox(self) -> Checkbox:
return WinCheckbox()
class MacFactory(GUIFactory):
def create_button(self) -> Button:
return MacButton()
def create_checkbox(self) -> Checkbox:
return MacCheckbox()
class Application:
def __init__(self, factory: GUIFactory) -> None:
self.button = factory.create_button()
self.checkbox = factory.create_checkbox()
def render(self) -> None:
self.button.paint()
self.checkbox.paint()
os_name = "Windows"
factory = WinFactory() if os_name == "Windows" else MacFactory()
Application(factory).render()
interface Button {
paint(): void;
}
interface Checkbox {
paint(): void;
}
class WinButton implements Button {
paint(): void {
console.log("Рисуем кнопку в стиле Windows.");
}
}
class WinCheckbox implements Checkbox {
paint(): void {
console.log("Рисуем чекбокс в стиле Windows.");
}
}
class MacButton implements Button {
paint(): void {
console.log("Рисуем кнопку в стиле macOS.");
}
}
class MacCheckbox implements Checkbox {
paint(): void {
console.log("Рисуем чекбокс в стиле macOS.");
}
}
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WinFactory implements GUIFactory {
createButton(): Button {
return new WinButton();
}
createCheckbox(): Checkbox {
return new WinCheckbox();
}
}
class MacFactory implements GUIFactory {
createButton(): Button {
return new MacButton();
}
createCheckbox(): Checkbox {
return new MacCheckbox();
}
}
class Application {
private readonly button: Button;
private readonly checkbox: Checkbox;
constructor(factory: GUIFactory) {
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
}
render(): void {
this.button.paint();
this.checkbox.paint();
}
}
const os = "Windows";
const factory: GUIFactory = os === "Windows" ? new WinFactory() : new MacFactory();
new Application(factory).render();
interface Button {
void paint();
}
interface Checkbox {
void paint();
}
class WinButton implements Button {
public void paint() {
System.out.println("Рисуем кнопку в стиле Windows.");
}
}
class WinCheckbox implements Checkbox {
public void paint() {
System.out.println("Рисуем чекбокс в стиле Windows.");
}
}
class MacButton implements Button {
public void paint() {
System.out.println("Рисуем кнопку в стиле macOS.");
}
}
class MacCheckbox implements Checkbox {
public void paint() {
System.out.println("Рисуем чекбокс в стиле macOS.");
}
}
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
class WinFactory implements GUIFactory {
public Button createButton() {
return new WinButton();
}
public Checkbox createCheckbox() {
return new WinCheckbox();
}
}
class MacFactory implements GUIFactory {
public Button createButton() {
return new MacButton();
}
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
class Application {
private final Button button;
private final Checkbox checkbox;
Application(GUIFactory factory) {
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
}
void render() {
button.paint();
checkbox.paint();
}
}
public class Program {
public static void main(String[] args) {
String os = "Windows";
GUIFactory factory = os.equals("Windows") ? new WinFactory() : new MacFactory();
new Application(factory).render();
}
}
interface Button {
fun paint()
}
interface Checkbox {
fun paint()
}
class WinButton : Button {
override fun paint() = println("Рисуем кнопку в стиле Windows.")
}
class WinCheckbox : Checkbox {
override fun paint() = println("Рисуем чекбокс в стиле Windows.")
}
class MacButton : Button {
override fun paint() = println("Рисуем кнопку в стиле macOS.")
}
class MacCheckbox : Checkbox {
override fun paint() = println("Рисуем чекбокс в стиле macOS.")
}
interface GUIFactory {
fun createButton(): Button
fun createCheckbox(): Checkbox
}
class WinFactory : GUIFactory {
override fun createButton(): Button = WinButton()
override fun createCheckbox(): Checkbox = WinCheckbox()
}
class MacFactory : GUIFactory {
override fun createButton(): Button = MacButton()
override fun createCheckbox(): Checkbox = MacCheckbox()
}
class Application(factory: GUIFactory) {
private val button = factory.createButton()
private val checkbox = factory.createCheckbox()
fun render() {
button.paint()
checkbox.paint()
}
}
fun main() {
val os = "Windows"
val factory: GUIFactory = if (os == "Windows") WinFactory() else MacFactory()
Application(factory).render()
}
Плюсы и минусы
| Плюсы | Минусы |
|---|---|
| Гарантирует совместимость создаваемых продуктов | Добавление новых семейств продуктов требует изменения фабрики |
| Изолирует код создания объектов от клиента | Усложняет систему за счёт дополнительных классов и интерфейсов |
| Следует принципу открытости/закрытости (OCP) | Труднее поддерживать при большом количестве семейств продуктов |
Заключение
Abstract Factory идеально подходит для создания семейств связанных объектов, когда важно сохранять их совместимость. Он делает систему гибкой, но требует тщательного проектирования и может быть избыточным для простых случаев.