Skip to content

Commit bdd8076

Browse files
committed
英語翻訳記事追加
1 parent 0705be0 commit bdd8076

1 file changed

Lines changed: 165 additions & 0 deletions

File tree

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
---
2+
title: GoF Design Patterns - Abstract Factory
3+
date: 2026-02-03
4+
category: Coding
5+
description: A practical guide to the Abstract Factory pattern from the GoF collection: concept, when to use it, a C++ implementation example, caveats, and references.
6+
tags: [Coding, DesignPattern]
7+
recommended: true
8+
thumbnail: assets/img/ogp.png
9+
---
10+
11+
Hello! I'm Pan-kun.
12+
13+
This entry covers the Abstract Factory pattern from the GoF (Gang of Four) design patterns.
14+
I'll give a practical explanation including sample code (C++), how to build it, when to use it, caveats, and references.
15+
16+
## Introduction
17+
18+
The Abstract Factory is a pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.
19+
20+
As a primary reference, here's the Wikipedia definition:
21+
22+
> "Provide an interface for creating families of related or dependent objects without specifying their concrete classes."
23+
> [https://en.wikipedia.org/wiki/Abstract_factory_pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern)
24+
25+
> "Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."
26+
> (Source: [https://en.wikipedia.org/wiki/Abstract_factory_pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern))
27+
28+
As the definitions indicate, this pattern allows the client to work only with abstract interfaces and remain unaware of which concrete products are being created. By swapping implementations, you can replace an entire theme (family of products) consistently.
29+
30+
## When to use it
31+
32+
Here are some typical scenarios where you might consider using Abstract Factory:
33+
34+
- When you want to switch UI themes or platform-dependent UI components as a group.
35+
- When you need to create a set of products that must be consistent with each other (for example, switching pairs like `Button` and `Checkbox`).
36+
- When implementations must be swappable at runtime or through configuration.
37+
38+
Alternatives and considerations:
39+
40+
- For simple cases, a `Simple Factory` (conditional creation) may be sufficient.
41+
- If you need to vary only a single product, `Factory Method` might be more appropriate.
42+
- Combining Abstract Factory with dependency injection (DI) improves testability.
43+
44+
## Structure (Elements)
45+
46+
- `AbstractFactory`: the factory interface for creating product families.
47+
- `ConcreteFactory`: implements the abstract factory and creates concrete products.
48+
- `AbstractProductA`, `AbstractProductB`: abstract product interfaces.
49+
- `ConcreteProductA1`, `ConcreteProductB1`: concrete product implementations.
50+
- `Client`: obtains products from the abstract factory and uses them via abstract interfaces.
51+
52+
A UML diagram is omitted here, but the above components form the basic structure.
53+
54+
## C++ Implementation Example
55+
56+
Below is a concise C++ sample implementing an Abstract Factory for a `Button` / `Checkbox` product family.
57+
58+
```cpp
59+
// AbstractFactory C++
60+
#include <memory>
61+
#include <iostream>
62+
#include <string>
63+
64+
// Abstract Product A: Button
65+
struct Button {
66+
virtual ~Button() = default;
67+
virtual std::string render() const = 0;
68+
};
69+
70+
// Abstract Product B: Checkbox
71+
struct Checkbox {
72+
virtual ~Checkbox() = default;
73+
virtual std::string render() const = 0;
74+
};
75+
76+
// Concrete product family 1: Windows
77+
struct WindowsButton : Button {
78+
std::string render() const override { return "WindowsButton"; }
79+
};
80+
struct WindowsCheckbox : Checkbox {
81+
std::string render() const override { return "WindowsCheckbox"; }
82+
};
83+
84+
// Concrete product family 2: Mac
85+
struct MacButton : Button {
86+
std::string render() const override { return "MacButton"; }
87+
};
88+
struct MacCheckbox : Checkbox {
89+
std::string render() const override { return "MacCheckbox"; }
90+
};
91+
92+
// Abstract Factory
93+
struct GUIFactory {
94+
virtual ~GUIFactory() = default;
95+
virtual std::unique_ptr<Button> createButton() const = 0;
96+
virtual std::unique_ptr<Checkbox> createCheckbox() const = 0;
97+
};
98+
99+
// Concrete Factory: Windows
100+
struct WindowsFactory : GUIFactory {
101+
std::unique_ptr<Button> createButton() const override {
102+
return std::make_unique<WindowsButton>();
103+
}
104+
std::unique_ptr<Checkbox> createCheckbox() const override {
105+
return std::make_unique<WindowsCheckbox>();
106+
}
107+
};
108+
109+
// Concrete Factory: Mac
110+
struct MacFactory : GUIFactory {
111+
std::unique_ptr<Button> createButton() const override {
112+
return std::make_unique<MacButton>();
113+
}
114+
std::unique_ptr<Checkbox> createCheckbox() const override {
115+
return std::make_unique<MacCheckbox>();
116+
}
117+
};
118+
119+
// Client depends on GUIFactory (depends on abstraction)
120+
void renderUI(const GUIFactory& factory) {
121+
auto btn = factory.createButton();
122+
auto chk = factory.createCheckbox();
123+
std::cout << "Render: " << btn->render() << ", " << chk->render() << "\n";
124+
}
125+
126+
int main() {
127+
WindowsFactory wf;
128+
MacFactory mf;
129+
130+
renderUI(wf); // Render: WindowsButton, WindowsCheckbox
131+
renderUI(mf); // Render: MacButton, MacCheckbox
132+
133+
return 0;
134+
}
135+
```
136+
137+
Key points from the sample:
138+
- `renderUI` does not know concrete classes; it just uses products provided by `GUIFactory`.
139+
- Adding a new theme (product family) does not require changes to `renderUI`.
140+
141+
## Advantages / Disadvantages
142+
143+
Advantages
144+
- You can create families of products consistently, making implementation swaps straightforward.
145+
- Clients are decoupled from concrete classes, improving portability and testability.
146+
- Introducing a new product family typically requires minimal changes to client code.
147+
148+
Disadvantages
149+
- Adding a new product *type* (a new AbstractProduct interface) requires modifying every `ConcreteFactory`, which can be costly.
150+
- If you pick the wrong abstraction granularity early, you may over-engineer and increase complexity.
151+
- Swapping implementations can affect serialization, APIs, and data formats, which may introduce compatibility issues.
152+
153+
## Conclusion
154+
155+
The Abstract Factory is a powerful pattern when you need to swap related product families as a whole.
156+
Before adopting it, evaluate the scope of products to be added, your test strategy, and the impact on APIs/serialization.
157+
Combining it with dependency injection improves testability and flexibility. Start small and extend abstractions as needed to avoid premature over-engineering.
158+
159+
References:
160+
161+
[!CARD](https://en.wikipedia.org/wiki/Abstract_factory_pattern)
162+
163+
I'll cover another GoF pattern next time. The code samples shown here are simplified for learning purposes — review and adapt them to your production requirements before use.
164+
165+
That's all from Pan-kun!

0 commit comments

Comments
 (0)