Implementing Structural Design Patterns
1. Implementing Adapter Pattern
Example: Adapt incompatible interface
interface PaymentGateway { Receipt charge(Money m); }
class StripeAdapter implements PaymentGateway {
private final StripeClient stripe;
public Receipt charge(Money m) {
var resp = stripe.createCharge(m.cents(), m.currency().code());
return new Receipt(resp.id(), resp.status());
}
}
2. Implementing Bridge Pattern
| Element | Role |
|---|---|
| Abstraction | Refined behavior |
| Implementor | Pluggable backend |
| Goal | Vary abstraction & implementation independently |
Example: Notification × Channel
interface Channel { void send(String to, String body); }
abstract class Notification {
protected final Channel channel;
Notification(Channel c) { this.channel = c; }
abstract void notify(User u);
}
class WelcomeNotification extends Notification { ... } // ↔ EmailChannel, SmsChannel
3. Implementing Composite Pattern
Example: Tree of components
interface FsNode { long size(); }
record File(String name, long size) implements FsNode {}
record Folder(String name, List<FsNode> children) implements FsNode {
public long size() { return children.stream().mapToLong(FsNode::size).sum(); }
}
4. Implementing Decorator Pattern
Example: Wrap and add behavior
interface DataSource { String read(); void write(String s); }
class EncryptedDataSource implements DataSource {
private final DataSource inner;
EncryptedDataSource(DataSource d) { this.inner = d; }
public String read() { return decrypt(inner.read()); }
public void write(String s) { inner.write(encrypt(s)); }
}
DataSource ds = new EncryptedDataSource(new CompressedDataSource(new FileDataSource("a.dat")));
5. Implementing Facade Pattern
| Element | Role |
|---|---|
| Facade | Unified high-level API |
| Subsystem | Hidden complex parts |
| Goal | Simplify client interaction |
Example: Order facade
class CheckoutFacade {
public Receipt checkout(Cart c) {
inventory.reserve(c);
var charge = payment.charge(c.total());
var order = orders.place(c, charge);
notifier.confirm(order);
return order.receipt();
}
}
6. Implementing Flyweight Pattern
| Concept | Detail |
|---|---|
| Intrinsic state | Shared, immutable |
| Extrinsic state | Passed in per use |
| Java examples | Integer.valueOf cache, String intern |
7. Implementing Proxy Pattern
| Variant | Use |
|---|---|
| Virtual | Lazy creation of expensive object |
| Protection | Access control checks |
| Remote | Wraps RPC stub |
| Smart reference | Logging, ref counting |
8. Implementing Repository Pattern
Example: Domain-owned port
public interface OrderRepository {
Optional<Order> findById(OrderId id);
void save(Order order);
List<Order> findByCustomer(CustomerId c, Pageable p);
}
9. Implementing Data Mapper Pattern
| Aspect | Detail |
|---|---|
| Goal | Decouple domain from persistence schema |
| Mechanism | Mapper class converts entity ↔ row/document |
| Tools | JPA @Entity, MapStruct, jOOQ |
10. Implementing Active Record Pattern
| Trait | Detail |
|---|---|
| Object = row | Carries data + persistence |
| Methods | save(), delete() on entity |
| Examples | Rails AR, Eloquent |
| Trade-off | Quick start, but mixes concerns |
11. Implementing Unit of Work Pattern
| Element | Role |
|---|---|
| Tracking | New, dirty, removed entities |
| Commit | Single transaction flush |
| Java | JPA EntityManager per request |
12. Implementing Module Pattern
| Lang | Mechanism |
|---|---|
| JS | IIFE / ES modules |
| Java | Package-private + module-info |
13. Implementing Delegation Pattern
Example: Forward to inner
class LoggingList<T> implements List<T> {
private final List<T> delegate;
public boolean add(T t) { log.info("add {}", t); return delegate.add(t); }
// ... forward all other methods
}
14. Understanding Wrapper Pattern
| Wrapper Type | Intent |
|---|---|
| Decorator | Add behavior |
| Adapter | Change interface |
| Proxy | Control access |
| Facade | Simplify subsystem |
15. Implementing Private Class Data Pattern
| Idea | Detail |
|---|---|
| Extract data | Move fields to inner data class |
| Restrict mutation | Set once via constructor |
| Java equivalent | Final field referencing record |
16. Understanding Adapter vs Decorator vs Proxy
| Pattern | Interface | Behavior |
|---|---|---|
| Adapter | Different from wrapped | Translation |
| Decorator | Same | Adds responsibility |
| Proxy | Same | Controls access |
17. Creating Lazy Initialization Proxy
Example: Virtual proxy
class LazyImageProxy implements Image {
private final String path;
private RealImage real;
public void render() {
if (real == null) real = new RealImage(path);
real.render();
}
}
18. Implementing Virtual Proxy
| When | Detail |
|---|---|
| Heavy object | Defer until needed |
| Network call | Avoid until first use |
| Frameworks | Hibernate lazy-loaded entities |
19. Using java.lang.reflect.Proxy
Example: Dynamic proxy
MyService proxy = (MyService) Proxy.newProxyInstance(
MyService.class.getClassLoader(),
new Class<?>[]{MyService.class},
(p, method, args) -> {
log.info("call {}", method.getName());
return method.invoke(target, args);
});
20. Using Class Delegation
| Lang | Mechanism |
|---|---|
| Kotlin | class A(b: B): I by b |
| Java | Manual forwarding methods |
21. Using Embedding for Delegation
| Lang | Mechanism |
|---|---|
| Go | Embed struct: type A struct { B } |
| Java equivalent | Inheritance or explicit delegation |
22. Using Extension Methods
| Lang | Mechanism |
|---|---|
| Kotlin/C# | fun String.lastChar() = ... |
| Java | Static utility methods |
23. Using Extension Methods as Decorators
| Idiom | Detail |
|---|---|
| Wrap result | fun List<T>.cached() = MemoList(this) |
| Java alt | Static decorator factory |
24. Using Module Mixins for Decoration
| Lang | Mechanism |
|---|---|
| Ruby | prepend Module |
| Java | Default methods on interfaces |
25. Using SimpleDelegator and DelegateClass
| Lang | Mechanism |
|---|---|
| Ruby | require 'delegate'; class X < SimpleDelegator |
| Java | Manual forwarding or dynamic proxy |