@booklib/skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/animation-at-work/SKILL.md +246 -0
- package/animation-at-work/assets/example_asset.txt +1 -0
- package/animation-at-work/references/api_reference.md +369 -0
- package/animation-at-work/references/review-checklist.md +79 -0
- package/animation-at-work/scripts/example.py +1 -0
- package/bin/skills.js +85 -0
- package/clean-code-reviewer/SKILL.md +292 -0
- package/clean-code-reviewer/evals/evals.json +67 -0
- package/data-intensive-patterns/SKILL.md +204 -0
- package/data-intensive-patterns/assets/example_asset.txt +1 -0
- package/data-intensive-patterns/references/api_reference.md +34 -0
- package/data-intensive-patterns/references/patterns-catalog.md +551 -0
- package/data-intensive-patterns/references/review-checklist.md +193 -0
- package/data-intensive-patterns/scripts/example.py +1 -0
- package/data-pipelines/SKILL.md +252 -0
- package/data-pipelines/assets/example_asset.txt +1 -0
- package/data-pipelines/references/api_reference.md +301 -0
- package/data-pipelines/references/review-checklist.md +181 -0
- package/data-pipelines/scripts/example.py +1 -0
- package/design-patterns/SKILL.md +245 -0
- package/design-patterns/assets/example_asset.txt +1 -0
- package/design-patterns/references/api_reference.md +1 -0
- package/design-patterns/references/patterns-catalog.md +726 -0
- package/design-patterns/references/review-checklist.md +173 -0
- package/design-patterns/scripts/example.py +1 -0
- package/domain-driven-design/SKILL.md +221 -0
- package/domain-driven-design/assets/example_asset.txt +1 -0
- package/domain-driven-design/references/api_reference.md +1 -0
- package/domain-driven-design/references/patterns-catalog.md +545 -0
- package/domain-driven-design/references/review-checklist.md +158 -0
- package/domain-driven-design/scripts/example.py +1 -0
- package/effective-java/SKILL.md +195 -0
- package/effective-java/assets/example_asset.txt +1 -0
- package/effective-java/references/api_reference.md +1 -0
- package/effective-java/references/items-catalog.md +955 -0
- package/effective-java/references/review-checklist.md +216 -0
- package/effective-java/scripts/example.py +1 -0
- package/effective-kotlin/SKILL.md +225 -0
- package/effective-kotlin/assets/example_asset.txt +1 -0
- package/effective-kotlin/references/api_reference.md +1 -0
- package/effective-kotlin/references/practices-catalog.md +1228 -0
- package/effective-kotlin/references/review-checklist.md +126 -0
- package/effective-kotlin/scripts/example.py +1 -0
- package/kotlin-in-action/SKILL.md +251 -0
- package/kotlin-in-action/assets/example_asset.txt +1 -0
- package/kotlin-in-action/references/api_reference.md +1 -0
- package/kotlin-in-action/references/practices-catalog.md +436 -0
- package/kotlin-in-action/references/review-checklist.md +204 -0
- package/kotlin-in-action/scripts/example.py +1 -0
- package/lean-startup/SKILL.md +250 -0
- package/lean-startup/assets/example_asset.txt +1 -0
- package/lean-startup/references/api_reference.md +319 -0
- package/lean-startup/references/review-checklist.md +137 -0
- package/lean-startup/scripts/example.py +1 -0
- package/microservices-patterns/SKILL.md +179 -0
- package/microservices-patterns/references/patterns-catalog.md +391 -0
- package/microservices-patterns/references/review-checklist.md +169 -0
- package/package.json +17 -0
- package/refactoring-ui/SKILL.md +236 -0
- package/refactoring-ui/assets/example_asset.txt +1 -0
- package/refactoring-ui/references/api_reference.md +355 -0
- package/refactoring-ui/references/review-checklist.md +114 -0
- package/refactoring-ui/scripts/example.py +1 -0
- package/storytelling-with-data/SKILL.md +238 -0
- package/storytelling-with-data/assets/example_asset.txt +1 -0
- package/storytelling-with-data/references/api_reference.md +379 -0
- package/storytelling-with-data/references/review-checklist.md +111 -0
- package/storytelling-with-data/scripts/example.py +1 -0
- package/system-design-interview/SKILL.md +213 -0
- package/system-design-interview/assets/example_asset.txt +1 -0
- package/system-design-interview/references/api_reference.md +582 -0
- package/system-design-interview/references/review-checklist.md +201 -0
- package/system-design-interview/scripts/example.py +1 -0
- package/using-asyncio-python/SKILL.md +242 -0
- package/using-asyncio-python/assets/example_asset.txt +1 -0
- package/using-asyncio-python/references/api_reference.md +267 -0
- package/using-asyncio-python/references/review-checklist.md +149 -0
- package/using-asyncio-python/scripts/example.py +1 -0
- package/web-scraping-python/SKILL.md +259 -0
- package/web-scraping-python/assets/example_asset.txt +1 -0
- package/web-scraping-python/references/api_reference.md +393 -0
- package/web-scraping-python/references/review-checklist.md +163 -0
- package/web-scraping-python/scripts/example.py +1 -0
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
# Design Patterns Catalog
|
|
2
|
+
|
|
3
|
+
Complete reference for all 23 GoF design patterns organized by category, based on
|
|
4
|
+
*Head First Design Patterns* by Eric Freeman & Elisabeth Robson.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Creational Patterns
|
|
9
|
+
|
|
10
|
+
Patterns that deal with object creation mechanisms, trying to create objects in a
|
|
11
|
+
manner suitable to the situation.
|
|
12
|
+
|
|
13
|
+
### Factory Method
|
|
14
|
+
|
|
15
|
+
**Intent:** Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
|
|
16
|
+
|
|
17
|
+
**Problem it solves:** Client code needs to create objects but shouldn't be coupled to specific concrete classes. New types may be added without modifying existing code.
|
|
18
|
+
|
|
19
|
+
**Participants:**
|
|
20
|
+
- **Creator** — Abstract class with the factory method (e.g., `PizzaStore`)
|
|
21
|
+
- **ConcreteCreator** — Subclass that implements the factory method (e.g., `NYPizzaStore`, `ChicagoPizzaStore`)
|
|
22
|
+
- **Product** — Interface for the objects created (e.g., `Pizza`)
|
|
23
|
+
- **ConcreteProduct** — Specific product classes (e.g., `NYStyleCheesePizza`)
|
|
24
|
+
|
|
25
|
+
**Key characteristics:**
|
|
26
|
+
- Creator declares abstract `factoryMethod()` returning Product type
|
|
27
|
+
- Subclasses override to return specific ConcreteProduct
|
|
28
|
+
- Creator may have default implementation
|
|
29
|
+
- Follows Dependency Inversion Principle: depend on abstractions, not concretions
|
|
30
|
+
- The "decision" of what to create is pushed to subclasses
|
|
31
|
+
|
|
32
|
+
**When to use:**
|
|
33
|
+
- A class can't anticipate the class of objects it must create
|
|
34
|
+
- A class wants its subclasses to specify the objects it creates
|
|
35
|
+
- You need to decouple client code from concrete classes
|
|
36
|
+
|
|
37
|
+
**Book example:** PizzaStore with orderPizza() template and createPizza() factory method. NYPizzaStore and ChicagoPizzaStore decide which pizza style to create.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Abstract Factory
|
|
42
|
+
|
|
43
|
+
**Intent:** Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
|
|
44
|
+
|
|
45
|
+
**Problem it solves:** A system needs to create families of related objects (e.g., all NY-style ingredients or all Chicago-style ingredients) that must be used together.
|
|
46
|
+
|
|
47
|
+
**Participants:**
|
|
48
|
+
- **AbstractFactory** — Interface declaring creation methods for each product type (e.g., `PizzaIngredientFactory`)
|
|
49
|
+
- **ConcreteFactory** — Implements creation for a specific family (e.g., `NYPizzaIngredientFactory`)
|
|
50
|
+
- **AbstractProduct** — Interface for each product type (e.g., `Dough`, `Sauce`, `Cheese`)
|
|
51
|
+
- **ConcreteProduct** — Family-specific products (e.g., `ThinCrustDough`, `MarinaraSauce`)
|
|
52
|
+
|
|
53
|
+
**Key characteristics:**
|
|
54
|
+
- Groups related factory methods into a single interface
|
|
55
|
+
- Ensures compatible products are created together
|
|
56
|
+
- Adding new product families is easy (new ConcreteFactory)
|
|
57
|
+
- Adding new product types requires changing the interface (harder)
|
|
58
|
+
- Often uses Factory Methods internally
|
|
59
|
+
|
|
60
|
+
**When to use:**
|
|
61
|
+
- A system must be independent of how its products are created
|
|
62
|
+
- A system must use one of several families of products
|
|
63
|
+
- Related products are designed to be used together and you need to enforce this constraint
|
|
64
|
+
|
|
65
|
+
**Book example:** PizzaIngredientFactory creates families of ingredients (dough, sauce, cheese, veggies, pepperoni, clams). NYPizzaIngredientFactory and ChicagoPizzaIngredientFactory produce region-specific ingredient sets.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Singleton
|
|
70
|
+
|
|
71
|
+
**Intent:** Ensure a class has only one instance and provide a global point of access to it.
|
|
72
|
+
|
|
73
|
+
**Problem it solves:** Some objects should only have one instance (thread pools, caches, dialog boxes, registry settings, logging objects, device drivers).
|
|
74
|
+
|
|
75
|
+
**Participants:**
|
|
76
|
+
- **Singleton** — Class with a private constructor and a static method that returns the sole instance
|
|
77
|
+
|
|
78
|
+
**Key characteristics:**
|
|
79
|
+
- Private constructor prevents external instantiation
|
|
80
|
+
- Static method (e.g., `getInstance()`) returns the unique instance
|
|
81
|
+
- Lazy initialization: instance created on first request
|
|
82
|
+
- Thread safety considerations are critical:
|
|
83
|
+
- **Eager initialization** — Create at class load time (simplest, always thread-safe)
|
|
84
|
+
- **synchronized method** — Thread-safe but may impact performance
|
|
85
|
+
- **Double-checked locking** — Only synchronize on first creation (use `volatile`)
|
|
86
|
+
- **Enum-based** — Most robust in Java (handles serialization and reflection)
|
|
87
|
+
|
|
88
|
+
**When to use:**
|
|
89
|
+
- Exactly one instance of a class is required
|
|
90
|
+
- The sole instance must be accessible from a well-known access point
|
|
91
|
+
- Be cautious: Singleton is often overused as a glorified global variable
|
|
92
|
+
|
|
93
|
+
**Pitfalls:**
|
|
94
|
+
- Multiple classloaders can create multiple instances
|
|
95
|
+
- Reflection can bypass private constructor
|
|
96
|
+
- Serialization can create new instances (unless handled)
|
|
97
|
+
- Makes unit testing harder due to global state
|
|
98
|
+
- Violates Single Responsibility (manages its own lifecycle + its actual job)
|
|
99
|
+
|
|
100
|
+
**Book example:** Chocolate boiler that must have only one instance to avoid overflow/waste scenarios. Thread-safety issues demonstrated with multiple threads.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Builder
|
|
105
|
+
|
|
106
|
+
**Intent:** Separate the construction of a complex object from its representation so that the same construction process can create different representations.
|
|
107
|
+
|
|
108
|
+
**Problem it solves:** Object creation involves many steps or configurations. Constructors with many parameters become unwieldy. Different representations need the same build process.
|
|
109
|
+
|
|
110
|
+
**Participants:**
|
|
111
|
+
- **Builder** — Interface specifying steps to build each part
|
|
112
|
+
- **ConcreteBuilder** — Implements the steps for a specific representation
|
|
113
|
+
- **Director** — Constructs the object using the Builder interface
|
|
114
|
+
- **Product** — The complex object being built
|
|
115
|
+
|
|
116
|
+
**Key characteristics:**
|
|
117
|
+
- Step-by-step construction process
|
|
118
|
+
- Director controls the algorithm; Builder knows the specifics
|
|
119
|
+
- Same construction process, different resulting products
|
|
120
|
+
- Product is retrieved from the Builder after construction completes
|
|
121
|
+
- Often uses fluent interface (method chaining) in modern implementations
|
|
122
|
+
|
|
123
|
+
**When to use:**
|
|
124
|
+
- Algorithm for creating a complex object should be independent of its parts
|
|
125
|
+
- Construction must allow different representations
|
|
126
|
+
- Constructor has too many parameters (telescoping constructor problem)
|
|
127
|
+
|
|
128
|
+
**Book example:** Vacation planner that builds different types of vacations (outdoor adventure, city sightseeing) using the same step-by-step planning process.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### Prototype
|
|
133
|
+
|
|
134
|
+
**Intent:** Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
|
|
135
|
+
|
|
136
|
+
**Problem it solves:** Creating new objects is expensive or complex, but similar objects already exist. You need many instances that differ slightly from existing ones.
|
|
137
|
+
|
|
138
|
+
**Participants:**
|
|
139
|
+
- **Prototype** — Interface declaring a `clone()` method
|
|
140
|
+
- **ConcretePrototype** — Implements clone to copy itself
|
|
141
|
+
- **Client** — Creates new objects by asking a prototype to clone itself
|
|
142
|
+
- **Registry/Manager** — Optional catalog of available prototypes
|
|
143
|
+
|
|
144
|
+
**Key characteristics:**
|
|
145
|
+
- Objects create copies of themselves
|
|
146
|
+
- Shallow vs deep copy considerations are important
|
|
147
|
+
- Avoids expensive creation from scratch
|
|
148
|
+
- Prototype registry allows dynamic addition of new types at runtime
|
|
149
|
+
- Client doesn't need to know concrete classes
|
|
150
|
+
|
|
151
|
+
**When to use:**
|
|
152
|
+
- Creating instances is expensive (database reads, complex computation)
|
|
153
|
+
- System should be independent of how its products are created
|
|
154
|
+
- Classes to instantiate are specified at runtime
|
|
155
|
+
- You need copies of existing objects with slight modifications
|
|
156
|
+
|
|
157
|
+
**Book example:** Monster registry where game creates new monsters by cloning prototypical instances rather than constructing from scratch each time.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Structural Patterns
|
|
162
|
+
|
|
163
|
+
Patterns that deal with object composition, creating relationships between objects
|
|
164
|
+
to form larger structures.
|
|
165
|
+
|
|
166
|
+
### Adapter
|
|
167
|
+
|
|
168
|
+
**Intent:** Convert the interface of a class into another interface that clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
|
|
169
|
+
|
|
170
|
+
**Problem it solves:** You have an existing class whose interface doesn't match what client code needs. You want to use a third-party class but its interface doesn't fit your system.
|
|
171
|
+
|
|
172
|
+
**Participants:**
|
|
173
|
+
- **Target** — The interface the client expects (e.g., `Duck`)
|
|
174
|
+
- **Adapter** — Translates calls from Target interface to Adaptee (e.g., `TurkeyAdapter`)
|
|
175
|
+
- **Adaptee** — The existing class with an incompatible interface (e.g., `Turkey`)
|
|
176
|
+
- **Client** — Works with the Target interface
|
|
177
|
+
|
|
178
|
+
**Key characteristics:**
|
|
179
|
+
- Object Adapter uses composition (wraps adaptee) — preferred
|
|
180
|
+
- Class Adapter uses multiple inheritance (where available)
|
|
181
|
+
- Adapter translates method calls, may need to handle mismatches in methods
|
|
182
|
+
- Can adapt a single class or multiple classes (facade-like adapter)
|
|
183
|
+
- The adaptee doesn't know it's being adapted
|
|
184
|
+
|
|
185
|
+
**When to use:**
|
|
186
|
+
- You want to use an existing class but its interface doesn't match your needs
|
|
187
|
+
- You want to create a reusable class that cooperates with unrelated classes
|
|
188
|
+
- You need to use several existing subclasses but can't adapt each by subclassing
|
|
189
|
+
|
|
190
|
+
**Book example:** TurkeyAdapter wrapping Turkey to make it work where Duck is expected. Also Enumeration-to-Iterator adapter for Java legacy collections.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### Bridge
|
|
195
|
+
|
|
196
|
+
**Intent:** Decouple an abstraction from its implementation so that the two can vary independently.
|
|
197
|
+
|
|
198
|
+
**Problem it solves:** You have a class hierarchy that is growing in two dimensions (e.g., different types AND different platforms). Without Bridge, you get a combinatorial explosion of subclasses.
|
|
199
|
+
|
|
200
|
+
**Participants:**
|
|
201
|
+
- **Abstraction** — High-level control interface (e.g., `RemoteControl`)
|
|
202
|
+
- **RefinedAbstraction** — Extension of the abstraction (e.g., `AdvancedRemoteControl`)
|
|
203
|
+
- **Implementor** — Interface for implementation classes (e.g., `TV`)
|
|
204
|
+
- **ConcreteImplementor** — Specific implementation (e.g., `SonyTV`, `LGTV`)
|
|
205
|
+
|
|
206
|
+
**Key characteristics:**
|
|
207
|
+
- Abstraction holds a reference to an Implementor
|
|
208
|
+
- Both hierarchies can be extended independently
|
|
209
|
+
- Avoids permanent binding between abstraction and implementation
|
|
210
|
+
- Composition replaces inheritance across two dimensions
|
|
211
|
+
- Changes to implementation don't affect client code
|
|
212
|
+
|
|
213
|
+
**When to use:**
|
|
214
|
+
- You want to avoid a permanent binding between abstraction and implementation
|
|
215
|
+
- Both abstractions and implementations should be extensible by subclassing
|
|
216
|
+
- Implementation changes should not impact clients
|
|
217
|
+
- You have a proliferation of classes resulting from coupled interface/implementation hierarchy
|
|
218
|
+
|
|
219
|
+
**Book example:** Remote controls (abstraction) and TVs (implementation). New remote features and new TV brands can be added independently without affecting each other.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### Composite
|
|
224
|
+
|
|
225
|
+
**Intent:** Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
|
|
226
|
+
|
|
227
|
+
**Problem it solves:** You need to represent hierarchical structures where both individual items and groups of items should be treated the same way (menus with sub-menus, file systems, organizational charts).
|
|
228
|
+
|
|
229
|
+
**Participants:**
|
|
230
|
+
- **Component** — Interface for all objects in the composition (e.g., `MenuComponent`)
|
|
231
|
+
- **Leaf** — Represents end objects with no children (e.g., `MenuItem`)
|
|
232
|
+
- **Composite** — Has children, implements child-related operations (e.g., `Menu`)
|
|
233
|
+
- **Client** — Manipulates objects through the Component interface
|
|
234
|
+
|
|
235
|
+
**Key characteristics:**
|
|
236
|
+
- Tree structure with uniform interface
|
|
237
|
+
- Leaves and composites implement the same interface
|
|
238
|
+
- Composites delegate to children and may add own behavior
|
|
239
|
+
- Trade-off: transparency (uniform interface) vs safety (separate leaf/composite types)
|
|
240
|
+
- Null Iterator pattern for leaves that have no children
|
|
241
|
+
- Component may throw UnsupportedOperationException for inapplicable methods
|
|
242
|
+
|
|
243
|
+
**When to use:**
|
|
244
|
+
- You want to represent part-whole hierarchies of objects
|
|
245
|
+
- You want clients to ignore the difference between compositions and individual objects
|
|
246
|
+
- All objects in the structure should be treated uniformly
|
|
247
|
+
|
|
248
|
+
**Book example:** Restaurant menu system with Menus containing MenuItems and sub-Menus. Printing the entire menu hierarchy traverses the composite tree uniformly.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Decorator
|
|
253
|
+
|
|
254
|
+
**Intent:** Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
|
|
255
|
+
|
|
256
|
+
**Problem it solves:** You need to add behavior to individual objects without affecting others of the same class. Subclassing for every combination leads to class explosion.
|
|
257
|
+
|
|
258
|
+
**Participants:**
|
|
259
|
+
- **Component** — Interface for objects that can have responsibilities added (e.g., `Beverage`)
|
|
260
|
+
- **ConcreteComponent** — Object to which additional responsibilities can be attached (e.g., `DarkRoast`)
|
|
261
|
+
- **Decorator** — Abstract class that wraps a Component and conforms to its interface (e.g., `CondimentDecorator`)
|
|
262
|
+
- **ConcreteDecorator** — Adds responsibilities (e.g., `Mocha`, `Whip`, `Soy`)
|
|
263
|
+
|
|
264
|
+
**Key characteristics:**
|
|
265
|
+
- Decorators have the same supertype as the objects they decorate
|
|
266
|
+
- One or more decorators can wrap an object
|
|
267
|
+
- Decorator adds its own behavior before/after delegating to the wrapped object
|
|
268
|
+
- Objects can be decorated at runtime with any combination
|
|
269
|
+
- Follows Open-Closed Principle: extend behavior without modifying existing code
|
|
270
|
+
- Can result in many small objects — harder to debug
|
|
271
|
+
|
|
272
|
+
**When to use:**
|
|
273
|
+
- You need to add responsibilities to individual objects dynamically and transparently
|
|
274
|
+
- Extending functionality by subclassing is impractical (too many combinations)
|
|
275
|
+
- You want to add behavior that can be withdrawn later
|
|
276
|
+
|
|
277
|
+
**Book example:** Starbuzz Coffee with beverages and condiments. Mocha(Whip(DarkRoast)) computes cost and description by wrapping, each decorator adding its price and label.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
### Facade
|
|
282
|
+
|
|
283
|
+
**Intent:** Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
|
|
284
|
+
|
|
285
|
+
**Problem it solves:** A subsystem has many classes with complex interactions. Clients need a simpler way to perform common tasks without understanding the subsystem's internals.
|
|
286
|
+
|
|
287
|
+
**Participants:**
|
|
288
|
+
- **Facade** — Provides simplified methods that delegate to subsystem classes (e.g., `HomeTheaterFacade`)
|
|
289
|
+
- **Subsystem classes** — The complex classes being simplified (e.g., `Amplifier`, `DVDPlayer`, `Projector`, `Screen`, `PopcornPopper`)
|
|
290
|
+
|
|
291
|
+
**Key characteristics:**
|
|
292
|
+
- Doesn't encapsulate subsystem — clients can still use subsystem directly if needed
|
|
293
|
+
- Simplifies the interface without adding new functionality
|
|
294
|
+
- Decouples client from subsystem classes
|
|
295
|
+
- Follows Principle of Least Knowledge (Law of Demeter)
|
|
296
|
+
- Can have multiple facades for different aspects of a subsystem
|
|
297
|
+
- Facade doesn't prevent direct access to subsystem when needed
|
|
298
|
+
|
|
299
|
+
**When to use:**
|
|
300
|
+
- You want to provide a simple interface to a complex subsystem
|
|
301
|
+
- There are many dependencies between clients and implementation classes
|
|
302
|
+
- You want to layer your subsystems
|
|
303
|
+
|
|
304
|
+
**Book example:** Home theater system where watchMovie() coordinates turning on amplifier, setting tuner, dimming lights, lowering screen, starting projector, and playing the DVD.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### Flyweight
|
|
309
|
+
|
|
310
|
+
**Intent:** Use sharing to support large numbers of fine-grained objects efficiently.
|
|
311
|
+
|
|
312
|
+
**Problem it solves:** An application needs a huge number of objects that share common state. Storing all state in each object would consume too much memory.
|
|
313
|
+
|
|
314
|
+
**Participants:**
|
|
315
|
+
- **Flyweight** — Interface through which flyweights receive and act on extrinsic state
|
|
316
|
+
- **ConcreteFlyweight** — Stores intrinsic (shared) state
|
|
317
|
+
- **FlyweightFactory** — Creates and manages flyweight objects, ensures proper sharing
|
|
318
|
+
- **Client** — Maintains extrinsic state, passes it to flyweights
|
|
319
|
+
|
|
320
|
+
**Key characteristics:**
|
|
321
|
+
- **Intrinsic state** — Stored in the flyweight, shared, context-independent (e.g., tree type, texture)
|
|
322
|
+
- **Extrinsic state** — Stored externally, context-dependent, passed to flyweight (e.g., position, age)
|
|
323
|
+
- Factory ensures flyweights are shared (returns existing instance or creates new)
|
|
324
|
+
- Dramatic reduction in number of objects
|
|
325
|
+
- Trade-off: computation time for looking up/computing extrinsic state
|
|
326
|
+
|
|
327
|
+
**When to use:**
|
|
328
|
+
- An application uses a large number of objects
|
|
329
|
+
- Storage costs are high due to sheer quantity
|
|
330
|
+
- Most object state can be made extrinsic
|
|
331
|
+
- Many groups of objects can be replaced by relatively few shared objects
|
|
332
|
+
- The application doesn't depend on object identity
|
|
333
|
+
|
|
334
|
+
**Book example:** Tree landscape with thousands of trees. Each tree type (oak, birch, pine) is a flyweight with shared texture/shape. Position (x, y) is extrinsic state.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
### Proxy
|
|
339
|
+
|
|
340
|
+
**Intent:** Provide a surrogate or placeholder for another object to control access to it.
|
|
341
|
+
|
|
342
|
+
**Problem it solves:** You need to control access to an object — for remote access, lazy loading, access control, logging, caching, or other cross-cutting concerns.
|
|
343
|
+
|
|
344
|
+
**Participants:**
|
|
345
|
+
- **Subject** — Interface shared by RealSubject and Proxy
|
|
346
|
+
- **RealSubject** — The actual object being proxied
|
|
347
|
+
- **Proxy** — Controls access to RealSubject, may create/manage it
|
|
348
|
+
|
|
349
|
+
**Proxy variants:**
|
|
350
|
+
- **Remote Proxy** — Represents an object in a different JVM/address space (e.g., Java RMI). The proxy handles network communication transparently
|
|
351
|
+
- **Virtual Proxy** — Creates expensive objects on demand. Displays a placeholder until the real object is loaded (e.g., image loading with placeholder)
|
|
352
|
+
- **Protection Proxy** — Controls access based on permissions (e.g., Java's dynamic Proxy with InvocationHandler checks caller rights)
|
|
353
|
+
- **Other variants** — Firewall proxy, caching proxy, synchronization proxy, smart reference proxy, copy-on-write proxy
|
|
354
|
+
|
|
355
|
+
**Key characteristics:**
|
|
356
|
+
- Proxy and RealSubject share the same interface
|
|
357
|
+
- Proxy holds a reference to RealSubject (or can create it)
|
|
358
|
+
- Proxy adds control logic before/after delegating to RealSubject
|
|
359
|
+
- Similar structure to Decorator, but different intent: Proxy controls access, Decorator adds behavior
|
|
360
|
+
- Java dynamic proxy creates proxy classes at runtime
|
|
361
|
+
|
|
362
|
+
**When to use:**
|
|
363
|
+
- You need a local representative for a remote object
|
|
364
|
+
- You want to create expensive objects only on demand
|
|
365
|
+
- You need to control access to the original object
|
|
366
|
+
- You want a smart reference (reference counting, locking, etc.)
|
|
367
|
+
|
|
368
|
+
**Book example:** Gumball machine monitoring via Remote Proxy (Java RMI). Virtual Proxy for CD cover images loading asynchronously. Protection Proxy using Java's InvocationHandler to control who can set ratings.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Behavioral Patterns
|
|
373
|
+
|
|
374
|
+
Patterns that deal with communication between objects, how objects interact and
|
|
375
|
+
distribute responsibility.
|
|
376
|
+
|
|
377
|
+
### Strategy
|
|
378
|
+
|
|
379
|
+
**Intent:** Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
|
|
380
|
+
|
|
381
|
+
**Problem it solves:** Multiple related classes differ only in their behavior. You need different variants of an algorithm. Conditional statements for selecting desired behavior become complex.
|
|
382
|
+
|
|
383
|
+
**Participants:**
|
|
384
|
+
- **Strategy** — Interface common to all supported algorithms (e.g., `FlyBehavior`)
|
|
385
|
+
- **ConcreteStrategy** — Implements the algorithm (e.g., `FlyWithWings`, `FlyNoWay`)
|
|
386
|
+
- **Context** — Configured with a Strategy, delegates to it (e.g., `Duck`)
|
|
387
|
+
|
|
388
|
+
**Key characteristics:**
|
|
389
|
+
- Context composes a Strategy via an interface field
|
|
390
|
+
- Behavior can be changed at runtime via setter
|
|
391
|
+
- Eliminates conditional statements for selecting behavior
|
|
392
|
+
- Follows "encapsulate what varies" and "program to interfaces"
|
|
393
|
+
- Favors composition over inheritance
|
|
394
|
+
- Each strategy is independently testable
|
|
395
|
+
|
|
396
|
+
**When to use:**
|
|
397
|
+
- Many related classes differ only in behavior
|
|
398
|
+
- You need different variants of an algorithm
|
|
399
|
+
- An algorithm uses data that clients shouldn't know about
|
|
400
|
+
- A class defines many behaviors via conditional statements
|
|
401
|
+
|
|
402
|
+
**Book example:** SimUDuck where ducks compose FlyBehavior and QuackBehavior. MallardDuck flies with wings, RubberDuck squeaks, and behaviors can be swapped at runtime with setFlyBehavior().
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### Observer
|
|
407
|
+
|
|
408
|
+
**Intent:** Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
|
|
409
|
+
|
|
410
|
+
**Problem it solves:** Multiple objects need to stay synchronized with another object's state. Tight coupling between the source of data and its consumers makes the system rigid.
|
|
411
|
+
|
|
412
|
+
**Participants:**
|
|
413
|
+
- **Subject** — Maintains list of observers, sends notifications (e.g., `WeatherData`)
|
|
414
|
+
- **Observer** — Interface for objects that should be notified (e.g., `Observer` with `update()`)
|
|
415
|
+
- **ConcreteSubject** — Stores state of interest, notifies observers when state changes
|
|
416
|
+
- **ConcreteObserver** — Maintains reference to ConcreteSubject, implements update (e.g., `CurrentConditionsDisplay`)
|
|
417
|
+
|
|
418
|
+
**Key characteristics:**
|
|
419
|
+
- Loose coupling: Subject knows only the Observer interface
|
|
420
|
+
- Observers can be added/removed at runtime
|
|
421
|
+
- **Push model** — Subject sends data with notification
|
|
422
|
+
- **Pull model** — Observer queries Subject for data after notification
|
|
423
|
+
- Subject doesn't need to know concrete observer classes
|
|
424
|
+
- Be careful with notification order dependencies
|
|
425
|
+
- Remember to unregister observers to prevent memory leaks
|
|
426
|
+
|
|
427
|
+
**When to use:**
|
|
428
|
+
- When a change to one object requires changing others, and you don't know how many
|
|
429
|
+
- When an object should notify others without making assumptions about who they are
|
|
430
|
+
- When you need a publish-subscribe mechanism
|
|
431
|
+
|
|
432
|
+
**Book example:** WeatherStation where WeatherData (Subject) notifies CurrentConditionsDisplay, StatisticsDisplay, and ForecastDisplay (Observers) whenever measurements change.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### Command
|
|
437
|
+
|
|
438
|
+
**Intent:** Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
|
|
439
|
+
|
|
440
|
+
**Problem it solves:** You need to issue requests to objects without knowing anything about the operation being requested or the receiver. You need to support undo/redo, queuing, logging.
|
|
441
|
+
|
|
442
|
+
**Participants:**
|
|
443
|
+
- **Command** — Interface declaring `execute()` (and optionally `undo()`)
|
|
444
|
+
- **ConcreteCommand** — Binds a receiver to an action (e.g., `LightOnCommand`)
|
|
445
|
+
- **Invoker** — Asks the command to carry out the request (e.g., `RemoteControl`)
|
|
446
|
+
- **Receiver** — Knows how to perform the actual work (e.g., `Light`, `Stereo`)
|
|
447
|
+
- **Client** — Creates commands and sets their receivers
|
|
448
|
+
|
|
449
|
+
**Key characteristics:**
|
|
450
|
+
- Decouples invoker from receiver
|
|
451
|
+
- Commands can be stored, queued, and logged
|
|
452
|
+
- **Undo** — Command stores previous state; `undo()` reverses `execute()`
|
|
453
|
+
- **Macro Command** — Command that executes a sequence of commands
|
|
454
|
+
- **NoCommand** (Null Object) — Placeholder command that does nothing; eliminates null checks
|
|
455
|
+
- Commands can be serialized for replay or remote execution
|
|
456
|
+
|
|
457
|
+
**When to use:**
|
|
458
|
+
- Parameterize objects with an action to perform
|
|
459
|
+
- Specify, queue, and execute requests at different times
|
|
460
|
+
- Support undo/redo functionality
|
|
461
|
+
- Support logging changes so they can be reapplied after a crash
|
|
462
|
+
- Structure a system around high-level operations built from primitives
|
|
463
|
+
|
|
464
|
+
**Book example:** Universal remote control where buttons are assigned commands. LightOnCommand, StereoOnWithCDCommand, etc. Undo button reverses last command. Party mode via MacroCommand.
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### Template Method
|
|
469
|
+
|
|
470
|
+
**Intent:** Define the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps without changing the algorithm's structure.
|
|
471
|
+
|
|
472
|
+
**Problem it solves:** Two or more classes have algorithms with the same structure but different steps. Duplicating the algorithm in each class violates DRY.
|
|
473
|
+
|
|
474
|
+
**Participants:**
|
|
475
|
+
- **AbstractClass** — Defines the template method and abstract primitive operations (e.g., `CaffeineBeverage`)
|
|
476
|
+
- **ConcreteClass** — Implements the primitive operations (e.g., `Tea`, `Coffee`)
|
|
477
|
+
|
|
478
|
+
**Key characteristics:**
|
|
479
|
+
- Template method defines the algorithm structure, calls abstract/hook methods
|
|
480
|
+
- **Abstract methods** — Subclasses MUST implement these steps
|
|
481
|
+
- **Hook methods** — Subclasses CAN override these; default (often empty) implementation provided
|
|
482
|
+
- **Hollywood Principle** — "Don't call us, we'll call you." Superclass controls when subclasses are called
|
|
483
|
+
- Template method itself should be `final` to prevent subclass overriding
|
|
484
|
+
- Strategy vs Template Method: Strategy uses composition, Template Method uses inheritance
|
|
485
|
+
|
|
486
|
+
**When to use:**
|
|
487
|
+
- Implement the invariant parts of an algorithm once and leave variable parts to subclasses
|
|
488
|
+
- Common behavior among subclasses should be factored into a common class to avoid duplication
|
|
489
|
+
- Control subclass extensions (hooks let subclasses extend at specific points)
|
|
490
|
+
|
|
491
|
+
**Book example:** CaffeineBeverage prepareRecipe() calls boilWater(), brew(), pourInCup(), addCondiments(). Tea and Coffee implement brew() and addCondiments() differently. Hook: customerWantsCondiments().
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
### Iterator
|
|
496
|
+
|
|
497
|
+
**Intent:** Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
|
|
498
|
+
|
|
499
|
+
**Problem it solves:** Collections have different internal structures (arrays, lists, hashtables) but clients need a uniform way to traverse them without knowing the internals.
|
|
500
|
+
|
|
501
|
+
**Participants:**
|
|
502
|
+
- **Iterator** — Interface for accessing and traversing elements (`hasNext()`, `next()`)
|
|
503
|
+
- **ConcreteIterator** — Implements Iterator for a specific aggregate
|
|
504
|
+
- **Aggregate** — Interface for creating an Iterator (`createIterator()`)
|
|
505
|
+
- **ConcreteAggregate** — Implements the Aggregate; returns appropriate ConcreteIterator
|
|
506
|
+
|
|
507
|
+
**Key characteristics:**
|
|
508
|
+
- Uniform traversal interface regardless of collection type
|
|
509
|
+
- Collection doesn't expose its internal structure
|
|
510
|
+
- Multiple iterators can traverse the same collection simultaneously
|
|
511
|
+
- Follows Single Responsibility Principle: collection manages elements, iterator manages traversal
|
|
512
|
+
- In Java, `java.util.Iterator` provides standard interface
|
|
513
|
+
- Internal vs external iterators (who controls traversal)
|
|
514
|
+
|
|
515
|
+
**When to use:**
|
|
516
|
+
- Access a collection's contents without exposing its internal representation
|
|
517
|
+
- Support multiple traversals of collections
|
|
518
|
+
- Provide a uniform interface for traversing different collection structures
|
|
519
|
+
|
|
520
|
+
**Book example:** Diner menu (array) and Pancake House menu (ArrayList) need a common way for a waitress to iterate. Each menu provides an Iterator, waitress uses the same loop for both.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
### State
|
|
525
|
+
|
|
526
|
+
**Intent:** Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
|
|
527
|
+
|
|
528
|
+
**Problem it solves:** An object's behavior depends on its state, and it must change behavior at runtime depending on that state. Large conditional statements test the current state and select behavior.
|
|
529
|
+
|
|
530
|
+
**Participants:**
|
|
531
|
+
- **State** — Interface defining behavior for each state (e.g., `State` with insertQuarter(), turnCrank(), etc.)
|
|
532
|
+
- **ConcreteState** — Each state implements behavior appropriate for that state (e.g., `HasQuarterState`, `SoldState`)
|
|
533
|
+
- **Context** — Maintains a current State instance, delegates behavior to it (e.g., `GumballMachine`)
|
|
534
|
+
|
|
535
|
+
**Key characteristics:**
|
|
536
|
+
- Eliminates large conditional blocks (switch/if-else on state)
|
|
537
|
+
- State transitions handled by state objects (or by context — design choice)
|
|
538
|
+
- Each state encapsulates its own behavior
|
|
539
|
+
- Similar class diagram to Strategy, but different intent:
|
|
540
|
+
- Strategy: client chooses algorithm, typically configured once
|
|
541
|
+
- State: transitions happen automatically based on context, behavior changes over time
|
|
542
|
+
- New states can be added without modifying existing state classes (Open-Closed Principle)
|
|
543
|
+
- Context delegates to current state for all state-dependent behavior
|
|
544
|
+
|
|
545
|
+
**When to use:**
|
|
546
|
+
- Object behavior depends on its state and changes at runtime
|
|
547
|
+
- Operations have large multipart conditional statements depending on state
|
|
548
|
+
- You want to make state transitions explicit
|
|
549
|
+
|
|
550
|
+
**Book example:** Gumball machine with NoQuarterState, HasQuarterState, SoldState, SoldOutState. Each state handles all actions (insert quarter, eject, turn crank, dispense) appropriately for its context.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
### Chain of Responsibility
|
|
555
|
+
|
|
556
|
+
**Intent:** Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
|
|
557
|
+
|
|
558
|
+
**Problem it solves:** Multiple objects may handle a request, and the handler isn't known a priori. The set of handlers and their order should be configurable.
|
|
559
|
+
|
|
560
|
+
**Participants:**
|
|
561
|
+
- **Handler** — Interface defining handleRequest(); may include successor reference
|
|
562
|
+
- **ConcreteHandler** — Handles requests it's responsible for; forwards others to successor
|
|
563
|
+
- **Client** — Initiates the request to a handler in the chain
|
|
564
|
+
|
|
565
|
+
**Key characteristics:**
|
|
566
|
+
- Request travels along the chain until handled (or falls off the end)
|
|
567
|
+
- Sender doesn't know which handler will process the request
|
|
568
|
+
- Chain can be configured dynamically
|
|
569
|
+
- Each handler decides: handle or pass along
|
|
570
|
+
- No guarantee the request will be handled (may need a default handler)
|
|
571
|
+
- Reduces coupling between sender and receiver
|
|
572
|
+
|
|
573
|
+
**When to use:**
|
|
574
|
+
- More than one object may handle a request and the handler is not known a priori
|
|
575
|
+
- You want to issue a request to one of several objects without specifying the receiver explicitly
|
|
576
|
+
- The set of handlers should be specified dynamically
|
|
577
|
+
|
|
578
|
+
**Book example:** Email handler chain: SpamHandler → FanHandler → ComplaintHandler → NewLocationHandler. Each handler checks if it should process the email, otherwise passes it to the next handler.
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
### Interpreter
|
|
583
|
+
|
|
584
|
+
**Intent:** Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
|
|
585
|
+
|
|
586
|
+
**Problem it solves:** You have a simple language or grammar that needs to be interpreted. Each rule in the grammar can be represented as a class.
|
|
587
|
+
|
|
588
|
+
**Participants:**
|
|
589
|
+
- **AbstractExpression** — Interface for interpret() operation
|
|
590
|
+
- **TerminalExpression** — Implements interpret for terminal symbols in the grammar
|
|
591
|
+
- **NonterminalExpression** — Implements interpret for grammar rules (contains other expressions)
|
|
592
|
+
- **Context** — Contains global information for the interpreter
|
|
593
|
+
- **Client** — Builds the abstract syntax tree and invokes interpret
|
|
594
|
+
|
|
595
|
+
**Key characteristics:**
|
|
596
|
+
- Each grammar rule becomes a class
|
|
597
|
+
- Abstract syntax tree (AST) represents sentences in the language
|
|
598
|
+
- Easy to change/extend the grammar by adding new expression classes
|
|
599
|
+
- Complex grammars become hard to maintain (use parser generators for those)
|
|
600
|
+
- Works best for simple, well-defined languages
|
|
601
|
+
|
|
602
|
+
**When to use:**
|
|
603
|
+
- The grammar is simple (complex grammars need parser generators)
|
|
604
|
+
- Efficiency is not a critical concern
|
|
605
|
+
- You need an easy way to interpret/evaluate a language
|
|
606
|
+
|
|
607
|
+
**Book example:** Musical notation interpreter where expressions represent notes, rests, and sequences. Each grammar rule is a class with an interpret method.
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
### Mediator
|
|
612
|
+
|
|
613
|
+
**Intent:** Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly.
|
|
614
|
+
|
|
615
|
+
**Problem it solves:** Many objects communicate with many others in complex ways. Direct references create a tangled web of dependencies that's hard to understand and modify.
|
|
616
|
+
|
|
617
|
+
**Participants:**
|
|
618
|
+
- **Mediator** — Interface defining communication between colleague objects
|
|
619
|
+
- **ConcreteMediator** — Coordinates communication between colleagues; knows all colleagues
|
|
620
|
+
- **Colleague** — Each object communicates through the mediator rather than directly with others
|
|
621
|
+
|
|
622
|
+
**Key characteristics:**
|
|
623
|
+
- Centralizes complex communication and control logic
|
|
624
|
+
- Colleagues only know the mediator, not each other
|
|
625
|
+
- Simplifies object protocols (many-to-many → many-to-one)
|
|
626
|
+
- Mediator can become a God Object if not careful
|
|
627
|
+
- Promotes loose coupling between colleagues
|
|
628
|
+
- Trade-off: complexity moves from distributed interactions to centralized mediator
|
|
629
|
+
|
|
630
|
+
**When to use:**
|
|
631
|
+
- A set of objects communicate in well-defined but complex ways
|
|
632
|
+
- Reusing an object is difficult because it refers to many other objects
|
|
633
|
+
- Behavior distributed between several classes should be customizable without subclassing
|
|
634
|
+
|
|
635
|
+
**Book example:** Home automation where an alarm clock, calendar, coffee maker, and sprinkler system communicate through a mediator. Calendar event triggers alarm, which triggers coffee maker, all coordinated by the mediator.
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
### Memento
|
|
640
|
+
|
|
641
|
+
**Intent:** Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
|
|
642
|
+
|
|
643
|
+
**Problem it solves:** You need to implement undo, checkpoint, or rollback functionality. Saving/restoring state directly would expose internal details and violate encapsulation.
|
|
644
|
+
|
|
645
|
+
**Participants:**
|
|
646
|
+
- **Originator** — Object whose state needs to be saved; creates and restores from Memento
|
|
647
|
+
- **Memento** — Stores the internal state of the Originator; opaque to other objects
|
|
648
|
+
- **Caretaker** — Responsible for keeping the Memento; never examines or modifies its contents
|
|
649
|
+
|
|
650
|
+
**Key characteristics:**
|
|
651
|
+
- Preserves encapsulation: only Originator can access Memento's internals
|
|
652
|
+
- Caretaker holds mementos but doesn't know their contents
|
|
653
|
+
- Can store multiple mementos for multi-level undo
|
|
654
|
+
- May be expensive if Originator state is large
|
|
655
|
+
- Consider incremental changes vs full snapshots
|
|
656
|
+
- Originator creates memento, Caretaker stores it, Originator restores from it
|
|
657
|
+
|
|
658
|
+
**When to use:**
|
|
659
|
+
- A snapshot of an object's state must be saved for later restoration
|
|
660
|
+
- A direct interface to obtaining the state would expose implementation details
|
|
661
|
+
- You need to implement undo/redo, checkpoints, or transactions
|
|
662
|
+
|
|
663
|
+
**Book example:** Save game state where the game (Originator) creates a Memento of its state, the system (Caretaker) stores it, and the game can restore to any saved state later.
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
### Visitor
|
|
668
|
+
|
|
669
|
+
**Intent:** Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
|
|
670
|
+
|
|
671
|
+
**Problem it solves:** You have a stable class hierarchy but need to add new operations frequently. Adding methods to each class for every new operation pollutes the interface and requires changing all classes.
|
|
672
|
+
|
|
673
|
+
**Participants:**
|
|
674
|
+
- **Visitor** — Interface declaring visit method for each element type
|
|
675
|
+
- **ConcreteVisitor** — Implements operations for each element type (e.g., `NutritionVisitor`, `PricingVisitor`)
|
|
676
|
+
- **Element** — Interface declaring accept(Visitor) method
|
|
677
|
+
- **ConcreteElement** — Implements accept by calling visitor.visit(this) (double dispatch)
|
|
678
|
+
- **ObjectStructure** — Collection of elements that can be iterated
|
|
679
|
+
|
|
680
|
+
**Key characteristics:**
|
|
681
|
+
- **Double dispatch** — Operation depends on both Visitor type AND Element type
|
|
682
|
+
- Element.accept(visitor) → visitor.visit(element): two method calls determine behavior
|
|
683
|
+
- Easy to add new operations (new Visitor class) without changing elements
|
|
684
|
+
- Hard to add new element types (must update all Visitors)
|
|
685
|
+
- Gathers related operations in a Visitor instead of spreading across element classes
|
|
686
|
+
- Elements must expose enough state for Visitors to work
|
|
687
|
+
|
|
688
|
+
**When to use:**
|
|
689
|
+
- An object structure contains many classes with differing interfaces and you want to perform operations that depend on concrete classes
|
|
690
|
+
- Many distinct/unrelated operations need to be performed on objects in a structure
|
|
691
|
+
- The classes defining the structure rarely change, but you often want to define new operations
|
|
692
|
+
|
|
693
|
+
**Book example:** Menu items with NutritionVisitor and PricingVisitor. Each visitor traverses menu items, computing nutritional info or prices without modifying the MenuItem classes.
|
|
694
|
+
|
|
695
|
+
---
|
|
696
|
+
|
|
697
|
+
## Compound Patterns
|
|
698
|
+
|
|
699
|
+
### MVC (Model-View-Controller)
|
|
700
|
+
|
|
701
|
+
**Intent:** Separate an application into three interconnected components to separate internal representations from the ways information is presented and accepted by the user.
|
|
702
|
+
|
|
703
|
+
**Patterns used:**
|
|
704
|
+
- **Observer** — Model notifies Views when state changes
|
|
705
|
+
- **Strategy** — View uses Controller as its strategy for handling user input
|
|
706
|
+
- **Composite** — View hierarchy is a composite structure (panels contain buttons, labels, etc.)
|
|
707
|
+
|
|
708
|
+
**Participants:**
|
|
709
|
+
- **Model** — Application data and business logic; notifies observers (views) of changes
|
|
710
|
+
- **View** — Renders the model's data; observes model for updates; delegates user actions to controller
|
|
711
|
+
- **Controller** — Takes user input from view, interprets it, and manipulates the model; acts as the strategy for the view
|
|
712
|
+
|
|
713
|
+
**Key characteristics:**
|
|
714
|
+
- Model is completely independent of View and Controller
|
|
715
|
+
- Views can be swapped without changing the Model
|
|
716
|
+
- Controllers can be swapped to change input handling behavior
|
|
717
|
+
- Multiple Views can observe the same Model simultaneously
|
|
718
|
+
- **Model 2 (Web MVC)** — Adapted for web: Controller is a servlet, View is a JSP/template, Model is a POJO/bean
|
|
719
|
+
- Clean separation of concerns enables independent testing and development
|
|
720
|
+
|
|
721
|
+
**When to use:**
|
|
722
|
+
- Building interactive applications where presentation and data should be decoupled
|
|
723
|
+
- Multiple views of the same data are needed
|
|
724
|
+
- User interface needs to be easily changeable or replaceable
|
|
725
|
+
|
|
726
|
+
**Book example:** DJ beat controller where BeatModel (Model) tracks BPM and notifies DJView (View) of changes. BeatController (Controller) handles user interactions like setting BPM and starting/stopping beats.
|