Skip to content

Commit bb3327b

Browse files
committed
英語記事調整
1 parent cb61ad1 commit bb3327b

4 files changed

Lines changed: 257 additions & 38 deletions

File tree

WebSite/content/other/blog_00032.en.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ recommended: true
88
thumbnail: assets/img/ogp.png
99
---
1010

11-
Hello! I'm Pan-kun.
11+
Hello! I'm Pan-kun.
1212

13-
This post covers the Builder pattern from the GoF (Gang of Four) design patterns.
14-
I explain it practically with sample code in C++, how to design it, when to apply it, and important caveats.
13+
This post covers the Builder pattern from the GoF (Gang of Four) design patterns.
14+
I explain it practically with sample code in C++, how to design it, when to apply it, and important caveats.
1515

1616
# Introduction
1717

18-
The Builder pattern separates the construction of a complex object from its representation, improving readability and extensibility of the creation process.
18+
The Builder pattern separates the construction of a complex object from its representation, improving readability and extensibility of the creation process.
1919

20-
I'll quote Wikipedia as a primary source:
20+
I'll quote Wikipedia as a primary source:
2121

2222
> "The intent of the Builder design pattern is to separate the construction of a complex object from its representation so that the same construction process can create different representations."
2323
> (Source: [https://en.wikipedia.org/wiki/Builder_pattern](https://en.wikipedia.org/wiki/Builder_pattern))
@@ -26,7 +26,7 @@ I'll quote Wikipedia as a primary source:
2626

2727
## Structure (Elements)
2828

29-
A typical composition includes:
29+
A typical composition includes:
3030

3131
- `Product`: the complex object to be constructed
3232
- `Builder`: defines steps like `BuildPartX()` and provides `GetResult()`
@@ -35,7 +35,7 @@ A typical composition includes:
3535

3636
## C++ Implementation Example
3737

38-
Below is a minimal C++ example. This is a typical pattern that uses a `Director`.
38+
Below is a minimal C++ example. This is a typical pattern that uses a `Director`.
3939

4040
```cpp
4141
// Product.h -- the object being constructed
@@ -108,31 +108,35 @@ int main() {
108108
}
109109
```
110110
111-
The key point of this implementation is the separation between the construction procedure (the Director) and the concrete construction steps (the ConcreteBuilder). You can achieve variety simply by replacing `ConcreteBuilder`.
111+
The key point of this implementation is the separation between the construction procedure (the Director) and the concrete construction steps (the ConcreteBuilder). You can achieve variety simply by replacing `ConcreteBuilder`.
112112
113113
## When to Use It
114114
115-
Representative cases where you should consider the Builder pattern:
115+
Representative cases where you should consider the Builder pattern:
116116
117117
- When a constructor has many parameters and most of them are optional (named/optional parameters or factories can be alternatives).
118118
- When you need staged or complex initialization and want to separate the initialization steps (useful for incremental verification in tests).
119119
- When you want to produce different representations from the same construction procedure (multiple `ConcreteBuilder` implementations).
120120
- When building immutable objects: the Builder assembles a mutable intermediate representation and returns an immutable object at the end for readability.
121121
122-
Alternatives:
122+
Alternatives:
123123
124124
- Language-level named/optional parameters (for concise cases).
125125
- `Factory Method` or `Abstract Factory` (when creation responsibilities are managed by subclasses or family groups).
126126
- Stepwise helper functions calling constructors (often sufficient for simple cases).
127127
128128
## Summary
129129
130-
The Builder pattern is a powerful pattern intended to separate construction procedure and representation. It is effective when dealing with complex initialization or variable representations. However, Builder introduces trade-offs around mutability, integration with dependency injection, and test design. Before adopting it, evaluate the impact on creation sites, serialization, and tests.
130+
The Builder pattern is a powerful pattern intended to separate construction procedure and representation.
131+
It is effective when dealing with complex initialization or variable representations.
132+
However, Builder introduces trade-offs around mutability, integration with dependency injection, and test design. Before adopting it, evaluate the impact on creation sites, serialization, and tests.
131133
132-
References and sources:
134+
References and sources:
133135
134136
[!CARD](https://en.wikipedia.org/wiki/Builder_pattern)
135137
136-
That's it for this post. Next time I'll cover another GoF pattern. The code shown here is simplified for learning purposes — when adopting patterns in production, make sure to adapt them to your project requirements.
138+
That's it for this post.
139+
Next time I'll cover another GoF pattern.
140+
The code shown here is simplified for learning purposes — when adopting patterns in production, make sure to adapt them to your project requirements.
137141
138142
Thanks for reading — Pan-kun!

WebSite/content/other/blog_00033.en.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@ thumbnail: assets/img/ogp.png
1010

1111
Hello! I'm Pan-kun.
1212

13-
This post covers the Adapter pattern from the GoF (Gang of Four) design patterns.
14-
I explain it practically, including a C++ sample, how to implement it, when to use it, pitfalls to watch out for, and a Mermaid diagram for visualization.
13+
This post covers the Adapter pattern from the GoF (Gang of Four) design patterns.
14+
I explain it practically, including a C++ sample, how to implement it, when to use it, pitfalls to watch out for, and a Mermaid diagram for visualization.
1515

1616
## Introduction
1717

18-
The Adapter pattern provides a wrapper that connects incompatible interfaces, allowing an existing class to be adapted to the interface expected by clients.
18+
The Adapter pattern provides a wrapper that connects incompatible interfaces, allowing an existing class to be adapted to the interface expected by clients.
1919

20-
Benefits:
20+
Benefits:
2121
- You can adapt existing code or third-party libraries to a new interface without changing their implementation.
2222

23-
Drawbacks:
23+
Drawbacks:
2424
- Proliferation of wrappers can scatter design responsibilities and reduce readability and maintainability.
2525
- The added indirection can also introduce runtime overhead.
2626

2727
## Use cases
2828

29-
Common scenarios where you would create an Adapter include:
29+
Common scenarios where you would create an Adapter include:
3030

3131
- Integrating a legacy API or library into a new application interface.
3232
- When different modules expose incompatible interfaces but you cannot modify the existing implementation.
3333
- Creating a thin boundary that makes it easy to swap implementations during testing (though using mocks can be simpler when applicable).
3434

3535
## Structure
3636

37-
An Adapter implements the Target interface and internally invokes the Adaptee's operations while performing any required conversions.
37+
An Adapter implements the Target interface and internally invokes the Adaptee's operations while performing any required conversions.
3838

3939
```mermaid
4040
classDiagram
@@ -55,7 +55,7 @@ classDiagram
5555

5656
## C++ implementation example
5757

58-
Below is a concise C++ example.
58+
Below is a concise C++ example.
5959

6060
```cpp
6161
// Example: the client expects to call Target::request()
@@ -100,10 +100,10 @@ std::unique_ptr<Target> target = std::make_unique<Adapter>(adaptee);
100100
target->request(); // the client only knows Target
101101
```
102102

103-
Key points:
103+
Key points:
104104
- Perform data-format conversion, error handling, and method mapping as needed.
105-
- There are inheritance-based and delegation-based adapters; choose according to your use case.
106-
In short: inheritance-based adapters leverage class inheritance, while delegation-based adapters implement an interface and forward calls to a contained object.
105+
- There are inheritance-based and delegation-based adapters; choose according to your use case.
106+
In short: inheritance-based adapters leverage class inheritance, while delegation-based adapters implement an interface and forward calls to a contained object.
107107

108108
## Implementation notes
109109

@@ -142,16 +142,16 @@ Typical bad practices when applying this pattern:
142142

143143
## Conclusion
144144

145-
The Adapter is a practical and commonly used pattern for bridging incompatible interfaces. However, careless proliferation of Adapters can complicate design. Make responsibilities explicit and localize translation logic when you use this pattern.
146-
Pay special attention to ownership, exception and error handling, performance, and testability when implementing an Adapter.
145+
The Adapter is a practical and commonly used pattern for bridging incompatible interfaces. However, careless proliferation of Adapters can complicate design. Make responsibilities explicit and localize translation logic when you use this pattern.
146+
Pay special attention to ownership, exception and error handling, performance, and testability when implementing an Adapter.
147147

148148
References:
149149

150150
[!CARD](https://sourcemaking.com/design_patterns/adapter)
151151

152152
[!CARD](https://en.wikipedia.org/wiki/Adapter_pattern)
153153

154-
That's it for now — next time I'll cover another GoF pattern.
155-
The examples in this article are simplified for learning purposes; evaluate them carefully against your requirements before adopting them in production.
154+
That's it for now — next time I'll cover another GoF pattern.
155+
The examples in this article are simplified for learning purposes; evaluate them carefully against your requirements before adopting them in production.
156156

157157
Thanks for reading — Pan-kun!
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
title: GoF Design Patterns - Bridge
3+
date: 2026-02-11
4+
category: Coding
5+
description: A practical guide to the Bridge pattern from the GoF collection:concepts, 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! This is Pan-kun.
12+
13+
This article covers the Bridge pattern from the GoF (Gang of Four) design patterns.
14+
I explain it practically, including sample code (C++), how to build it, when to use it, and important caveats.
15+
16+
## Introduction
17+
18+
The Bridge pattern separates an abstraction from its implementation so the two can vary independently.
19+
When you use class inheritance, abstraction and implementation often become tightly coupled.
20+
The Bridge pattern provides a flexible alternative that lets you change either side without affecting the other.
21+
22+
> The Bridge pattern is a software design pattern defined by the Gang of Four. It decouples an abstraction from its implementation so that the two can vary independently.
23+
>
24+
> Source: [Bridge pattern - Wikipedia](https://en.wikipedia.org/wiki/Bridge_pattern)
25+
26+
[!CARD](https://en.wikipedia.org/wiki/Bridge_pattern)
27+
28+
## Use Cases
29+
30+
Here are some typical situations where you might consider applying the Bridge pattern:
31+
32+
**When you do not want to permanently bind abstraction and implementation.**
33+
Useful if you need to select or switch implementations at runtime.
34+
**When you need to extend both the abstraction hierarchy and the implementation hierarchy.**
35+
Keeps the number of classes under control by managing extension at independent layers.
36+
**When you want implementation changes to have minimal impact on clients.**
37+
Hides implementation details and can minimize recompilation scope (in C++ this is related to the Pimpl idiom).
38+
**When many classes share similar implementation with small variations.**
39+
Splitting the feature hierarchy from the implementation hierarchy reduces code duplication.
40+
41+
## Structure
42+
43+
To implement the Bridge pattern you typically create four roles of classes:
44+
45+
1. **Abstraction**
46+
- The top-level class in the feature hierarchy.
47+
- Holds a reference to an `Implementor` and delegates work to it.
48+
2. **RefinedAbstraction**
49+
- Inherits from `Abstraction` and adds or refines behavior.
50+
- Defines concrete combinations of feature behavior.
51+
3. **Implementor**
52+
- The top-level interface (or abstract class) for the implementation hierarchy.
53+
- Defines the low-level API used by `Abstraction`.
54+
4. **ConcreteImplementor**
55+
- Implements the `Implementor` interface concretely.
56+
- Contains platform-specific or library-dependent code.
57+
58+
Below is a UML representation. Notice the separation between the feature (abstraction) class hierarchy and the implementation class hierarchy — they are literally bridged.
59+
60+
```mermaid
61+
classDiagram
62+
class Abstraction {
63+
-impl : Implementor
64+
+operation()
65+
}
66+
67+
class RefinedAbstraction {
68+
+operation()
69+
+extendedOperation()
70+
}
71+
72+
class Implementor {
73+
<<interface>>
74+
+operationImpl()
75+
}
76+
77+
class ConcreteImplementorA {
78+
+operationImpl()
79+
}
80+
81+
class ConcreteImplementorB {
82+
+operationImpl()
83+
}
84+
85+
Abstraction <|-- RefinedAbstraction
86+
Abstraction o-- Implementor
87+
Implementor <|.. ConcreteImplementorA
88+
Implementor <|.. ConcreteImplementorB
89+
```
90+
91+
## C++ Implementation Example
92+
93+
Here we use a drawing example.
94+
We separate the abstract concept of a "shape" from a concrete "drawing API" implementation.
95+
96+
This lets you add new shapes (e.g., rectangles, circles) on the shape side or add new drawing methods (e.g., OpenGL, DirectX) on the implementation side without changing the other.
97+
98+
```cpp
99+
// Drawing API interface
100+
class DrawingAPI {
101+
public:
102+
virtual ~DrawingAPI() = default;
103+
virtual void drawCircle(double x, double y, double radius) = 0;
104+
};
105+
106+
// Concrete Drawing API 1
107+
class DrawingAPI1 : public DrawingAPI {
108+
public:
109+
void drawCircle(double x, double y, double radius) override {
110+
std::cout << "API1.circle at " << x << ":" << y << " radius " << radius << std::endl;
111+
}
112+
};
113+
114+
// Concrete Drawing API 2
115+
class DrawingAPI2 : public DrawingAPI {
116+
public:
117+
void drawCircle(double x, double y, double radius) override {
118+
std::cout << "API2.circle at " << x << ":" << y << " radius " << radius << std::endl;
119+
}
120+
};
121+
122+
// Abstract shape class
123+
class Shape {
124+
protected:
125+
DrawingAPI* drawingAPI; // holds reference to Implementor
126+
127+
public:
128+
Shape(DrawingAPI* api) : drawingAPI(api) {}
129+
virtual ~Shape() = default;
130+
131+
virtual void draw() = 0; // high-level operation
132+
virtual void resizeByPercentage(double pct) = 0; // high-level operation
133+
};
134+
135+
// Concrete shape: circle
136+
class CircleShape : public Shape {
137+
private:
138+
double x, y, radius;
139+
140+
public:
141+
CircleShape(double x, double y, double radius, DrawingAPI* api)
142+
: Shape(api), x(x), y(y), radius(radius) {}
143+
144+
void draw() override {
145+
// Delegate actual drawing to the drawingAPI implementation
146+
drawingAPI->drawCircle(x, y, radius);
147+
}
148+
149+
void resizeByPercentage(double pct) override {
150+
radius *= (1.0 + pct / 100.0);
151+
}
152+
};
153+
154+
int main() {
155+
DrawingAPI1 api1;
156+
DrawingAPI2 api2;
157+
158+
// Same conceptual "circle" but instantiated with different drawing APIs
159+
CircleShape circle1(1, 2, 3, &api1);
160+
CircleShape circle2(5, 7, 11, &api2);
161+
162+
circle1.resizeByPercentage(10);
163+
circle2.resizeByPercentage(10);
164+
165+
std::cout << "--- Circle 1 with API 1 ---" << std::endl;
166+
circle1.draw();
167+
168+
std::cout << "--- Circle 2 with API 2 ---" << std::endl;
169+
circle2.draw();
170+
171+
return 0;
172+
}
173+
174+
// Output
175+
// --- Circle 1 with API 1 ---
176+
// API1.circle at 1:2 radius 3.3
177+
// --- Circle 2 with API 2 ---
178+
// API2.circle at 5:7 radius 12.1
179+
```
180+
181+
In this example, `Shape` holds a pointer to a `DrawingAPI`.
182+
When `CircleShape::draw` is invoked, the actual drawing logic is delegated to the `DrawingAPI` implementation.
183+
184+
## Advantages / Disadvantages
185+
186+
### Advantages
187+
188+
- **Implementation hiding and reduced dependencies**
189+
Client code needs to know only the abstraction (`Abstraction`) and not the implementation details. This can shorten compile times and enable looser coupling.
190+
- **Improved extensibility**
191+
You can extend the feature hierarchy and the implementation hierarchy independently. Adding a new feature doesn't affect implementation classes, and adding a new implementation doesn't affect feature classes.
192+
- **Runtime implementation switching**
193+
By replacing the `Implementor` object at runtime you can change behavior dynamically.
194+
195+
### Disadvantages
196+
197+
- **Increased design complexity**
198+
For small systems where simple inheritance is sufficient, Bridge can increase the number of classes and unnecessarily complicate the structure.
199+
- **Potentially reduced readability**
200+
Because behavior is delegated from the abstraction to implementation classes, understanding the full behavior may require navigating multiple classes, which can make the code less intuitive.
201+
202+
## Conclusion
203+
204+
The Bridge pattern is a powerful technique to keep systems flexible by separating feature extension from implementation extension.
205+
It truly shines in large projects where future change requirements are unclear.
206+
However, it can be overengineering for small projects; a good rule is to introduce it when you actually see class explosion or when refactoring for clearer separation.
207+
208+
References:
209+
210+
[!CARD](https://en.wikipedia.org/wiki/Bridge_pattern)
211+
212+
That's all for now — next time I'll cover another GoF pattern.
213+
The sample implementations shown here are simplified for learning purposes. Evaluate carefully before adopting them in production.
214+
215+
Thanks for reading — Pan-kun!

0 commit comments

Comments
 (0)