Design Patterns: Focus on the Problems They Solve, Not Just Their Names
The article explains why memorizing design pattern names is insufficient, introduces core design principles (SRP, OCP, LSP, DIP, ISP, LoD), and walks through seven high‑frequency patterns—Singleton, Factory, Adapter, Decorator, Proxy, Observer, and Strategy—using an evolving order‑processing system to show how each pattern addresses changeability and extensibility.
Learning design patterns often falls into a trap: you memorize names like Singleton, Factory, Adapter, Observer, but when faced with a real scenario you cannot recognize which pattern applies. This article first defines the problem to solve:
When requirements keep changing, how can code be modified less, stay extensible, and avoid ripple effects?
01 A Growing Order System
Initially the order system only supports Alipay:
Create Order → Alipay Payment → Decrease Inventory → Send SMSLater new requirements appear:
Add WeChat Pay
Add Bank Card Pay
Add Full Reduction and Membership Discount
Add Points after successful payment
Integrate a completely different legacy payment system
Add permission check and logging before calling payment serviceIf all logic is piled into OrderService, the class becomes huge with many if branches:
if Alipay ...
else if WeChat ...
else if Bank Card ...
if regular user ...
else if member ...
else if using coupon ...
Deduct inventory ...
Add points ...
Send SMS ...
Write log ...Each new requirement forces modifications to existing stable code, which is exactly what design principles and patterns aim to prevent.
Isolate change so that new features are added by "adding code" rather than repeatedly modifying stable code.
02 Design Principles: Spotting Unhealthy Code
Principles guide the direction of good design; they are not concrete code templates. Their ultimate goals are:
High Cohesion: related responsibilities stay together.
Low Coupling: different modules depend on each other as little as possible.Single Responsibility Principle (SRP)
A class should have only one responsibility. For example, an Order class handles orders, a Payment service handles payments, and a Notification service handles notifications. If a class both calculates price, deducts inventory, sends SMS, and writes logs, any requirement change may affect it.
A class should change for only one reason.
Open/Closed Principle (OCP)
Software should be open for extension but closed for modification. When adding WeChat Pay, the ideal approach is to add a WeChatPay implementation instead of repeatedly changing the existing payment flow.
For foreseeable changes, prefer completing them through extension.
Liskov Substitution Principle (LSP)
Subclasses must be replaceable for their base class without breaking behavior. If both Alipay and WeChat Pay implement PayService, any code depending on PayService should work with either implementation.
A subclass can replace its parent without breaking the original contract.
Dependency Inversion Principle (DIP)
High‑level modules should depend on abstractions, not concrete implementations.
Bad: OrderService directly depends on WeChatPay class. Good: OrderService → PayService interface
WeChatPay, Alipay → implement PayServiceThis allows swapping payment methods without changing the order workflow.
Interface Segregation Principle (ISP)
Interfaces should be small and specific; clients should not be forced to depend on methods they do not need.
Large interface: Pay, Refund, Installment, Invoice, Points ExchangeIf a particular payment method only supports two of these, the interface should be split.
Do not force clients to depend on methods they don’t use.
Law of Demeter (LoD)
Objects should know as little as possible about the internal details of other objects. OrderService calls NotificationService.send() OrderService should not manipulate the internal gateway, template, or connection objects of NotificationService.
Communicate only with direct friends to reduce dependencies.
03 Three Shelves for Design Patterns
Design patterns can be placed on three shelves:
Creational: how objects are created
Structural: how objects are composed
Behavioral: how objects collaborateToday we focus on seven high‑frequency patterns:
Creational: Singleton, Factory
Structural: Adapter, Decorator, Proxy
Behavioral: Observer, Strategy04 Creational Patterns
Singleton
Problem: The system needs only one instance of a class (e.g., configuration manager, logger).
Ensure a class has exactly one instance and provide a global access point.
Only one main power switch for the whole buildingKeywords: unique instance, global access.
Factory
Problem: Object creation is complex and callers should not depend on concrete classes.
The order system only states: "I need a WeChatPay object".
OrderService → PaymentFactory → WeChatPay
→ AlipayThe factory encapsulates the creation process, reducing coupling between client and concrete classes.
Customer places product request, factory produces itKeywords: encapsulate creation, client does not new, decouple from concrete classes.
05 Structural Patterns
Adapter
Legacy payment system provides oldPay() while the new system expects pay(). An adapter converts the interface:
New System → Payment Adapter → Legacy SystemThe adapter does not add payment functionality; it only translates interfaces. Plug types differ, add an adapter Keywords: incompatible interfaces, interface conversion, legacy integration.
Decorator
When the basic payment functionality exists, we may want to add features dynamically (logging, retry, statistics, risk check) without modifying the original object.
Wrap the original object layer by layer A basic milk tea can be enhanced with pearls, cream, and coconut jellyKeywords: do not modify original, dynamic enhancement, layered wrapping.
Proxy
Clients access the real payment service through a proxy, which can perform permission checks, caching, logging, remote calls, or lazy loading before delegating.
User → Payment Proxy → Real Payment Service Before meeting a person, go through an agentKeywords: control access, permissions, caching, remote proxy.
06 Behavioral Patterns
Observer
After an order is created, several services need to react (inventory, points, SMS). The order publishes an "order created" event; subscribers handle the work.
Order Event
├── Inventory Handler
├── Points Handler
└── SMS NotificationDefine a one‑to‑many dependency: when one object changes, all dependents are notified and update.
Public account publishes an article, multiple subscribers receive the notificationKeywords: one‑to‑many, one change notifies many, publish‑subscribe.
Strategy
When calculating order discounts, multiple algorithms may apply (full reduction, membership discount, coupon, new‑user discount). Each algorithm is encapsulated and interchangeable at runtime.
OrderService → DiscountStrategy interface
→ FullReductionStrategy
→ MembershipStrategy
→ CouponStrategyEncapsulate a family of algorithms and make them interchangeable.
To the same destination, you can choose bus, subway, or taxiKeywords: multiple algorithms, interchangeable, runtime selection.
07 Applying the Seven Patterns to the Order System
Payment objects are created by a factory
Different discount algorithms use the Strategy pattern
Legacy payment interface is integrated via an Adapter
Payment calls go through a Proxy for permission and logging
Additional capabilities are added dynamically with Decorators
After successful order, an Observer notifies inventory, points, and SMS services
A globally unique configuration object can be a SingletonThese patterns are not mutually exclusive; a single workflow can combine multiple patterns (e.g., Factory creates Strategy objects, Proxy controls access to them, Decorator adds extra abilities).
08 Exam Identification Table
Only one instance → Singleton
Do not let client directly create concrete objects → Factory
Incompatible interfaces need conversion → Adapter
Do not modify original object, add functionality dynamically → Decorator
Control access, permissions, caching, remote call → Proxy
One change notifies multiple objects → Observer
Multiple algorithms interchangeable → Strategy
Add new features without modifying old code → Open/Closed Principle
Program to interfaces, not implementations → Dependency Inversion Principle
A class handles only one responsibility → Single Responsibility Principle
Subclass can replace parent without breaking behavior → Liskov Substitution Principle
Interface should be small and specific → Interface Segregation Principle
Object should know little about others' internals → Law of Demeter09 Hands‑On Task
Draw three shelves labeled "Design Patterns" → Creational, Structural, Behavioral. Place the seven patterns on the appropriate shelves and sketch a simple illustration for each (e.g., Singleton as a main power switch, Factory as a production line, Adapter as a plug adapter, etc.). Then narrate the order‑processing flow using those patterns.
10 Self‑Test
Answer the questions first, then check the answers provided. A score of 8 or higher is required to proceed to Day 19.
1. Creational, Structural, Behavioral
2. Open/Closed Principle
3. Dependency Inversion Principle
4. Single Responsibility Principle
5. Adapter Pattern
6. Decorator Pattern
7. Proxy Pattern
8. Observer Pattern
9. Strategy Pattern
10. Client vs. concrete object creationThe key takeaway: principles tell you the direction of good design; patterns show concrete ways to handle common problems.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
