โหมดมืด
บทที่ 3 — Design Patterns
Design Pattern = solution ที่ใช้ซ้ำสำหรับ problem ที่เจอบ่อย
หลังจบบท คุณจะ:
- รู้จัก pattern ที่ใช้บ่อยจริง (ไม่ใช่ 23 ตัวของ GoF ทั้งหมด)
- เห็นว่า pattern ไหนใช้เมื่อไหร่
- เห็น pattern ใน Spring, React ที่ใช้อยู่ทุกวัน
- ไม่ "ยัด pattern" ที่ไม่จำเป็น
ตัวอย่างก่อน: pattern คืออะไรในชีวิตจริง
ลองนึกถึงสถานการณ์: คุณต้องเลือก algorithm sort (bubble, quick, merge) — เปลี่ยนได้ตามต้องการ → นี่คือ Strategy pattern ตัวอย่างจาก code ที่เคยเขียน:
java
// เคย if/else เลือก algorithm?
if (type.equals("BUBBLE")) bubbleSort(items);
else if (type.equals("QUICK")) quickSort(items);แค่ตั้งชื่อให้รู้จักกัน "นี่คือ Strategy" — สื่อสารทีมรู้เรื่องทันที
Pattern = vocabulary — ทำให้สื่อกันได้ ("ใช้ Strategy ที่นี่") — ไม่ใช่ goal
💡 หมายเหตุยุค 2020+: ภาษา modern (Java 8+, Kotlin, TS, Python) ลดความจำเป็นของหลาย pattern ลง — Strategy = function, Singleton = DI container (Spring, Guice), Factory = DI container, Observer = callback / RxJS / EventEmitter อ่าน pattern เป็น vocabulary ไม่ใช่ เป้าหมาย
1. ประเภท Design Patterns (GoF, 1994)
🔤 GoF = Gang of Four (แก๊งสี่คน) — ชื่อเล่นของผู้เขียน 4 คนแห่งหนังสือ Design Patterns ปี 1994 ที่จัดหมวด pattern ออกเป็น 3 ประเภทด้านล่าง
ผู้เขียน 4 คน (พิมพ์ในชื่อหนังสือเรียงตามชื่อ):
- Erich Gamma (เอ-ริช แกม-มา)
- Richard Helm (ริ-ชาร์ด เฮล์ม)
- Ralph Johnson (รัล์ฟ จอห์น-สัน)
- John Vlissides (จอห์น วลิส-ซิ-เดส)
3 ประเภทใหญ่
| ประเภท | ทำอะไร | ตัวอย่าง |
|---|---|---|
| Creational (ครี-เอ-ชั่น-แนล = สร้าง) | สร้าง object | Factory, Builder, Singleton |
| Structural (สตรัค-เจอ-รัล = โครงสร้าง) | combine object (ประกอบ object เข้าด้วยกัน) | Adapter, Decorator, Facade |
| Behavioral (บี-เฮฟ-วิ-เออ-รัล = พฤติกรรม) | interaction ของ object (การโต้ตอบกันระหว่าง object) | Strategy, Observer, Command |
23 GoF patterns — ตารางอ้างอิงพร้อมคำอ่าน
| # | ประเภท | Pattern | คำอ่าน | ความหมายไทย |
|---|---|---|---|---|
| 1 | Creational | Abstract Factory | แอ๊บ-สแตร็คท์ แฟค-โท-รี่ | โรงงานของโรงงาน (สร้างตระกูล object) |
| 2 | Creational | Builder | บิ้ล-เดอร์ | ผู้สร้าง (ทีละขั้น) |
| 3 | Creational | Factory Method | แฟค-โท-รี่ เม-ธ็อด | วิธีโรงงาน |
| 4 | Creational | Prototype | โพร-โท-ไทป์ | ต้นแบบ (clone) |
| 5 | Creational | Singleton | ซิง-เกิ้ล-ตัน | แบบเดี่ยว (instance เดียว) |
| 6 | Structural | Adapter | อะ-แด๊พ-เตอร์ | หัวแปลง |
| 7 | Structural | Bridge | บริดจ์ | สะพาน (แยก abstraction กับ implementation) |
| 8 | Structural | Composite | คอม-โพ-สิท | โครงสร้างต้นไม้ |
| 9 | Structural | Decorator | เด-คอ-เร-เตอร์ | ตัวประดับ/ตัวห่อเพิ่มของ |
| 10 | Structural | Facade | ฟา-ซ้าด | ด้านหน้า/หน้ากาก |
| 11 | Structural | Flyweight | ฟลาย-เวท | น้ำหนักเบา (แชร์ object) |
| 12 | Structural | Proxy | พร็อก-ซี่ | ตัวแทน |
| 13 | Behavioral | Chain of Responsibility | เชน ออฟ รี-สปอน-ซิ-บิ-ลิ-ตี้ | ลูกโซ่ความรับผิดชอบ |
| 14 | Behavioral | Command | คอม-แมนด์ | คำสั่ง (encapsulate action) |
| 15 | Behavioral | Interpreter | อิน-เทอร์-พรี-เตอร์ | ตัวตีความ (parser) |
| 16 | Behavioral | Iterator | อิ-เท-เรเตอร์ | ตัววนซ้ำ |
| 17 | Behavioral | Mediator | มี-เดีย-เตอร์ | ผู้ประสานงานกลาง |
| 18 | Behavioral | Memento | เม-เม็น-โต้ | บันทึก/snapshot |
| 19 | Behavioral | Observer | ออบ-เซิร์ฟ-เวอร์ | ผู้สังเกต/ผู้ติดตาม |
| 20 | Behavioral | State | สเตท | สถานะ |
| 21 | Behavioral | Strategy | สแตร-ทิ-จี้ | กลยุทธ์ (สลับ algorithm) |
| 22 | Behavioral | Template Method | เท็ม-เพลท เม-ธ็อด | โครงวิธีการ |
| 23 | Behavioral | Visitor | วิ-ซิ-เตอร์ | ผู้เยี่ยม (operation ข้าม class) |
หนังสือนี้ — focus 10 patterns ที่ใช้บ่อย
Part 1: Creational
2. Factory — สร้าง object โดยไม่ระบุ class
🔤 Factory pattern (แฟค-โท-รี่ = รูปแบบ "โรงงาน" สร้าง object) — client ไม่ต้องรู้ว่า new class ตัวไหน บอก factory แค่ "ขอแบบนี้" พอ
ใช้เมื่อ: ต้องสร้าง object หลายแบบที่ implement interface เดียวกัน + ตัวเลือกอาจเพิ่มในอนาคต อย่าใช้เมื่อ: มีแค่ 1-2 class + ไม่เพิ่ม → new ตรง ๆ ง่ายกว่า
Factory pattern ย้ายการตัดสินใจ "สร้าง object ตัวไหน" ออกจาก client ไปไว้ที่เดียว — แทนที่จะมี if/else new ... กระจายทุกที่ client แค่บอก "ขอ payment processor แบบ STRIPE" แล้ว factory จัดการให้ ทำให้เพิ่มชนิดใหม่ได้โดยไม่ต้องแก้ client (JDBC, Spring @Bean ก็เป็น factory):
java
// ❌ Client knows concrete class
PaymentProcessor p;
if (type.equals("STRIPE")) p = new StripeProcessor(apiKey, secret);
else if (type.equals("PAYPAL")) p = new PayPalProcessor(clientId, secret);java
// ✅ Factory
class PaymentProcessorFactory {
public static PaymentProcessor create(String type) {
return switch (type) {
case "STRIPE" -> new StripeProcessor(getStripeConfig());
case "PAYPAL" -> new PayPalProcessor(getPaypalConfig());
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}
PaymentProcessor p = PaymentProcessorFactory.create(type);💡 Java 14+ switch expression:
switch (x) { case "A" -> ...; case "B" -> ...; }คือ syntax ใหม่ — return ค่าโดยตรง ไม่ต้องเขียนbreak(ผู้ใช้ Java 8/11 ใช้switch (x) { case "A": return ...; }แทน)
Factory vs Abstract Factory — ต่างยังไง?
⚠️ คน confuse บ่อย — เป็น 2 pattern แยกกัน:
- Factory (Factory Method) — สร้าง product เดียว (เช่น
PaymentProcessor) โดยไม่ระบุ class ตรง ๆ ใช้เมื่อ "ขอ product 1 ชิ้นแบบไม่ระบุ concrete class"- Abstract Factory — สร้าง ตระกูล (family) ของ product หลายตัวที่เข้ากัน (เช่น Button + Input + Modal ที่ทุกตัวเป็นธีม Material) ใช้เมื่อ "ขอชุดของของที่ต้องเข้ากันทั้งชุด"
Abstract Factory — ตระกูล class
สมมุติทำ UI library — ทุกธีม (Material, Tailwind) มี Button/Input/Modal ที่ "เข้าธีมกัน" — Abstract Factory การันตีว่าทั้งชุดจะเป็นธีมเดียวกัน
java
interface UIComponentFactory {
Button createButton(); // ปุ่ม
Input createInput(); // ช่องกรอกข้อความ
Modal createModal(); // หน้าต่าง popup
}
class MaterialUIFactory implements UIComponentFactory { ... } // ทุก component สไตล์ Material
class TailwindUIFactory implements UIComponentFactory { ... } // ทุก component สไตล์ TailwindButton/Input/Modal เป็น UI component ทั่ว ๆ ไปที่ library อย่าง Material UI / Bootstrap / Tailwind UI มีให้ใช้ — ที่นี่ใช้เป็นตัวอย่างเฉย ๆ ไม่ต้องเข้าใจ implementation
ใน Real World
- JDBC —
Connection conn = DriverManager.getConnection(url);(Driver = factory) - Spring
@Beanmethod = factory method Optional.of(x),List.of(...)= factory
3. Builder — สร้าง object ที่มี option เยอะ
🔤 Builder (บิ้ล-เดอร์ = ผู้สร้าง) — สร้าง object ทีละ field แบบ chain method telescoping constructor (เทเลส-โค-ปิ้ง = แบบกล้องโทรทรรศน์/ขยายต่อกัน) — มี constructor overload หลายตัว แต่ละตัวยาวขึ้นเรื่อย ๆ
ใช้เมื่อ: object มี field เยอะ (5+) หรือมี optional field เยอะ อย่าใช้เมื่อ: มี field 2-3 ตัวที่ required ทั้งหมด → constructor ปกติพอ
object ที่มี field เยอะ (โดยเฉพาะ optional) ถ้าใช้ constructor จะกลายเป็น "telescoping constructor" ที่อ่านไม่ออก (new User("Anna", null, 25, null, ...)) — Builder แก้ด้วยการ set ทีละ field แบบมีชื่อ อ่านง่ายและบังคับ required field ได้:
java
// ❌ Telescoping constructor
new User(name, email, age, phone, address, city, country, role, isActive, ...);
new User("Anna", "a@x.com", 25);
new User("Anna", "a@x.com", 25, "0812345678");
// 8 constructor overload — readable ไหม?java
// ✅ Builder
User user = User.builder()
.name("Anna")
.email("a@x.com")
.age(25)
.phone("0812345678")
.role("ADMIN")
.build();Lombok @Builder
java
@Builder
@Data
public class User {
private String name;
private String email;
private int age;
private String phone;
}→ Auto-generate builder
ใน Real World
- HTTP request —
Request.builder().url(...).header(...).body(...).build() - Spring's
RestClient.builder()... - StringBuilder —
new StringBuilder().append("a").append("b").toString() - SQL DSL —
select("name").from("users").where(...).build()
4. Singleton — instance เดียวทั้ง app
🔤 Singleton (ซิง-เกิ้ล-ตัน = แบบเดี่ยว) — class ที่มี instance เดียวใน app ทั้งหมด
⚠️ เริ่มต้นอ่านที่นี่ก่อน — Singleton ถือเป็น anti-pattern ในโค้ดแอปทั่วไป
ในยุค DI container (Spring, Guice, Dagger) เกือบทุกกรณีให้ใช้ DI scope แทนการเขียน Singleton เอง — เพราะ:
- Global state ที่ซ่อนอยู่ — ใครก็เรียก
getInstance()ได้ทุกที่ ผ่านไม่ผ่าน method signature ก็ไม่รู้- Test ยาก — mock ไม่ได้ง่าย ๆ (static method) → unit test ผูกกับ instance จริง
- Hidden coupling — class ที่เรียก
Database.getInstance()ผูกกับDatabaseแน่น ไม่มีทาง inject ตัวอื่น- Thread safety ยุ่ง — ถ้าเขียนเองพลาดง่ายมาก (ดูตัวอย่าง ❌ ด้านล่าง)
- Replace ยาก — เปลี่ยน implementation ต้องแก้ทุกที่ที่เรียก
แนวทาง modern: ให้ DI container จัดการ lifecycle (
@Component+ Spring สร้าง singleton ให้ — mock ได้ง่าย, inject แทน inject test double ได้) → ดูตอน ใน Spring ด้านล่าง
java
// ❌ Classic — NOT thread-safe (อย่าใช้ในโลกจริง)
class Database {
private static Database instance;
private Database() {}
public static Database getInstance() {
if (instance == null) instance = new Database(); // ❌ race condition!
return instance;
}
}🐛 bug: ถ้า 2 thread เรียก
getInstance()พร้อมกัน ทั้งคู่อาจเห็นinstance == nullแล้วต่างคนnew Database()คนละตัว → instance เลย "2 ตัว" → ทำลายหลัก singleton + อาจ leak resource (DB connection คู่กัน) วิธีแก้ canonical คือ double-checked locking กับvolatileหรือใช้ Holder idiom (ดูถัดไป)
Thread-safe + lazy (Bill Pugh's idiom)
java
// ✅ Initialization-on-demand Holder idiom (Bill Pugh)
class Database {
private static class Holder {
static final Database INSTANCE = new Database();
}
public static Database getInstance() {
return Holder.INSTANCE;
}
private Database() {}
}ทำไม thread-safe: JVM การันตีว่า class จะ load ครั้งเดียว + initialize static field ครั้งเดียวเท่านั้น (Java Language Specification §12.4) — Holder class ถูก load ตอนเรียก Holder.INSTANCE ครั้งแรกเท่านั้น → lazy + thread-safe โดยไม่ต้องใช้ synchronized (ซึ่งจะช้าทุก call)
⚠️ caveat: ถ้า
Databaseconstructorthrow→Holderclass fail to initialize → call ครั้งถัดไปจะได้NoClassDefFoundError(cryptic — debug ลำบาก) วิธีแก้: จัดการ exception ใน constructor หรือใช้ factory method ที่ handle error ชัดเจน
ใช้ Singleton ได้เมื่อ?
✅ Logger, Configuration
✅ DB connection pool
✅ Cache instance
❌ Business service → use DI (Spring container manages "singleton" for you)
ใน Spring
java
@Service
class UserService { ... }Spring default scope = singleton — แต่เป็น managed singleton → mock + test ง่าย
🧭 Singleton pattern vs. Spring managed singleton — ต่างกันยังไง?
- GoF Singleton pattern — class จัดการ instance ของตัวเอง (
getInstance()) + global state → anti-pattern- Spring managed singleton —
@Serviceclass ปกติ ที่ Spring container เก็บ 1 instance ไว้แล้ว inject ให้ผู้ใช้ — class ไม่รู้ ว่าเป็น singleton (testable + replaceable) → OKความต่าง = ใคร own lifecycle: class เองตอนแรก, container ตอนหลัง
Part 2: Structural
5. Adapter — แปลง interface
🔤 Adapter (อะ-แด๊พ-เตอร์ = หัวแปลง) — เหมือนหัวแปลงปลั๊กไฟ (220V → USB)
ใช้เมื่อ: ต้องใช้ class/library ภายนอกที่ interface ไม่ตรงกับของเรา + แก้ class นั้นไม่ได้ อย่าใช้เมื่อ: คุมทั้งสองฝั่งได้ → แก้ interface ตรง ๆ ดีกว่า
Adapter เหมือนหัวแปลงปลั๊กไฟ — เมื่อ library ภายนอกมี interface ไม่ตรงกับที่ระบบเราใช้ Adapter ห่อมันให้เข้ากับ interface ของเรา ทำให้ใช้ของเก่า/ของนอกได้โดยไม่ต้องแก้ทั้งสองฝั่ง (เช่น Arrays.asList() แปลง array เป็น List):
java
// External lib มี class นี้
class LegacyXmlPaymentApi {
public String processXml(String xmlRequest) { ... }
}
// แต่ระบบเราใช้ interface
interface PaymentProcessor {
PaymentResult process(PaymentRequest req);
}
// ✅ Adapter
class LegacyXmlPaymentAdapter implements PaymentProcessor {
private final LegacyXmlPaymentApi legacy = new LegacyXmlPaymentApi();
@Override
public PaymentResult process(PaymentRequest req) {
String xml = toXml(req); // placeholder — แปลง object → XML string
String responseXml = legacy.processXml(xml);
return parseResponse(responseXml); // placeholder — แปลง XML string → PaymentResult
}
}
toXml()/parseResponse()ในตัวอย่างเป็น placeholder ที่จะใช้ XML library (เช่น JAXB, Jackson XML) implement ในของจริง — ที่นี่เน้นแสดงรูปแบบ Adapter
→ ใช้ legacy API กับ modern interface ได้
ใน Real World
- Java Stream
Arrays.asList()— adapt array → List - Spring's
MessageSourceAccessor— wrap MessageSource - React
useStatewrapper around component class API
6. Decorator — เพิ่มความสามารถโดยไม่แก้ class เดิม
🔤 Decorator (เด-คอ-เร-เตอร์ = ตัวประดับ/ตัวห่อเพิ่มของ) — ห่อ object เดิมเพื่อเพิ่มความสามารถ + ห่อซ้อนได้
ใช้เมื่อ: ต้องการเพิ่มความสามารถ (logging, retry, caching) โดยไม่แก้ class เดิม + ผสมแบบยืดหยุ่น อย่าใช้เมื่อ: behavior มีแค่ 1-2 ตัว → inheritance ง่ายกว่า + เร็วกว่า
Decorator ห่อ object เดิมเพื่อเพิ่มความสามารถโดยไม่แก้ class เดิม — และ wrap ซ้อนกันได้ (กาแฟ + นม + น้ำตาล) เป็น composition แทน inheritance ตามหลัก OCP เจอบ่อยใน Java I/O (BufferedReader(InputStreamReader(...))) และ React HOC:
java
import java.math.BigDecimal;
interface Coffee {
BigDecimal cost(); // ✅ BigDecimal กับเงิน (ไม่ใช่ double — บทที่ 0 mindset)
String description();
}
class BasicCoffee implements Coffee {
public BigDecimal cost() { return new BigDecimal("50.00"); }
public String description() { return "Coffee"; }
}
class MilkDecorator implements Coffee {
private final Coffee coffee;
public MilkDecorator(Coffee coffee) { this.coffee = coffee; }
public BigDecimal cost() { return coffee.cost().add(new BigDecimal("15.00")); }
public String description() { return coffee.description() + " + Milk"; }
}
class SugarDecorator implements Coffee {
private final Coffee coffee;
public SugarDecorator(Coffee coffee) { this.coffee = coffee; }
public BigDecimal cost() { return coffee.cost().add(new BigDecimal("5.00")); }
public String description() { return coffee.description() + " + Sugar"; }
}
// ใช้
Coffee order = new SugarDecorator(new MilkDecorator(new BasicCoffee()));
order.cost(); // 70.00
order.description(); // "Coffee + Milk + Sugar"ใน Real World
- Java I/O:
new BufferedReader(new InputStreamReader(new FileInputStream(...)))— แต่ละชั้นเพิ่มความสามารถ (file → bytes → chars → buffered lines) เป็นตัวอย่าง Decorator คลาสสิก - React HOC:
withAuth(withTheme(MyComponent)) - Spring AOP:
@Transactionalครอบ method หนึ่ง — สร้าง proxy ห่อ method เดิมแล้วเพิ่ม transaction management ก่อน/หลัง → เป็น Decorator (@Cacheable,@Asyncก็ใช้กลไกเดียวกัน) ตัวอื่นเช่น Middleware (Express, Koa), Servlet Filter ก็แนวคิดเดียวกัน — ไว้อ่านเจาะลึกในบท Spring
7. Facade — Interface เดียวที่ครอบหลาย sub-system
🔤 Facade (ฟา-ซ้าด — รากฝรั่งเศส = ด้านหน้า/หน้ากาก) — เหมือนพนักงานต้อนรับโรงแรม: client คุยกับคนเดียว เบื้องหลังมีหลายแผนกทำงาน
ใช้เมื่อ: ระบบมี sub-system ซับซ้อนหลายตัว + ต้องการ API เรียบง่ายให้ใช้ อย่าใช้เมื่อ: มี sub-system ไม่กี่ตัว → Facade เพิ่ม layer โดยไม่จำเป็น
💡 หลักการที่หนุน Facade คือ Law of Demeter ("Don't Talk to Strangers" — อย่าคุยกับคนแปลกหน้า) เสนอโดย Ian Holland และทีม Demeter project (Northeastern University, 1987) — กฎคือ: object ควรคุยกับ "เพื่อนใกล้ตัว" เท่านั้น (field, parameter, ตัวเอง) ไม่ใช่ chain ลึก ๆ เช่น
order.getCustomer().getAddress().getCity()— Facade ลดการที่ client ต้องคุยข้าม sub-system ตรง ๆ
เมื่อการทำงานหนึ่งต้องประสานหลาย sub-system (checkout = inventory + payment + shipping + notification) client ที่เรียกตรงทุกตัวจะซับซ้อนและผูกแน่น — Facade ให้ interface เดียวที่ครอบทั้งหมด client เรียก checkout() ทีเดียว ส่วนความซับซ้อนซ่อนอยู่หลัง facade:
java
// ❌ Client deal with 5 sub-systems
class CheckoutFlow {
public void checkout(Order order) {
InventoryService inv = new InventoryService();
if (!inv.reserve(order)) throw new ...;
PaymentGateway gw = new PaymentGateway();
PaymentResult result = gw.charge(order.total(), order.card());
if (!result.success()) {
inv.release(order);
throw new ...;
}
ShippingService ship = new ShippingService();
ship.createShipment(order);
NotificationService notif = new NotificationService();
notif.sendOrderConfirmation(order);
}
}java
// ✅ Facade
class CheckoutFacade {
private final InventoryService inventory;
private final PaymentGateway payment;
private final ShippingService shipping;
private final NotificationService notification;
public OrderConfirmation checkout(Order order) {
try {
inventory.reserve(order);
payment.charge(order.total(), order.card());
shipping.createShipment(order);
notification.sendOrderConfirmation(order);
return new OrderConfirmation(order.getId());
} catch (Exception e) {
// rollback logic
throw e;
}
}
}
// Client
checkoutFacade.checkout(order); // ⭐ simple
inventory,payment,shipping,notificationในตัวอย่างเป็น service ของเราเอง (@Serviceclass ใน Spring) ไม่ใช่ library ภายนอก — เขียนเป็น placeholder name เพื่อสื่อภาพรวม
→ Client ใช้ 1 interface — ไม่ต้องรู้ inventory + payment + shipping
ใน Real World
- Spring
JdbcTemplate= facade over JDBC API - jQuery = facade over DOM API
- AWS SDK = facade over AWS REST API
Part 3: Behavioral
8. Strategy — ⭐ ใช้บ่อยที่สุด
🔤 Strategy (สแตร-ทิ-จี้ = กลยุทธ์) — สลับ algorithm ได้โดยไม่แก้ code เดิม
ใช้เมื่อ: มีหลาย algorithm/พฤติกรรมที่สลับกันได้ + จะเพิ่มในอนาคต อย่าใช้เมื่อ: มีแค่ 1 algorithm + ไม่เปลี่ยน — Strategy เพิ่ม abstraction โดยไม่จำเป็น
💡 ในภาษา modern: Strategy = function ที่ส่งเข้าไป (lambda, function value) ไม่ต้องมี class ก็ได้ → ใช้ higher-order function แทน class hierarchy เพราะง่ายและตรงกว่า
(เห็นใน OCP บทที่ 2)
java
interface SortStrategy<T> {
List<T> sort(List<T> items);
}
class BubbleSort<T extends Comparable<T>> implements SortStrategy<T> { ... }
class QuickSort<T extends Comparable<T>> implements SortStrategy<T> { ... }
class MergeSort<T extends Comparable<T>> implements SortStrategy<T> { ... }
class Sorter<T> {
private final SortStrategy<T> strategy;
public Sorter(SortStrategy<T> strategy) { this.strategy = strategy; }
public List<T> sort(List<T> items) {
return strategy.sort(items);
}
}
// ใช้
Sorter<Integer> s = new Sorter<>(new QuickSort<>());Modern Strategy = Lambda
java
class Sorter<T> {
public List<T> sort(List<T> items, Comparator<T> comparator) {
// ...
}
}
sorter.sort(items, (a, b) -> a.compareTo(b));
sorter.sort(items, Comparator.comparing(User::getName)); // ดูบท Java functional ภายหลัง
Comparatorคือ functional interface ใน Java (ดูในบท Java/Functional ภายหลัง) — รับ lambda หรือ method reference (User::getName) ได้
→ Strategy pattern ใน 1 line
เทียบ 3 ภาษา — ในภาษาที่ function เป็น first-class, Strategy "หายไป" กลายเป็นแค่ฟังก์ชัน
insight สำคัญ: GoF ออกแบบ Strategy ด้วย class + interface เพราะ Java ยุคเก่าส่งฟังก์ชันไปมาไม่ได้ — พอภาษารองรับ function เป็นค่าได้ (Java ยุคใหม่, JS/TS, Python) "strategy" ก็คือตัวฟังก์ชันที่ส่งเข้าไปตรง ๆ
typescript
// TypeScript — strategy = ฟังก์ชันที่ส่งเข้าไป ไม่ต้องมี class/interface
type SortStrategy<T> = (a: T, b: T) => number;
function sortBy<T>(items: T[], strategy: SortStrategy<T>): T[] {
return [...items].sort(strategy);
}
sortBy(users, (a, b) => a.name.localeCompare(b.name)); // เปลี่ยน strategy = เปลี่ยนฟังก์ชันpython
# Python — ส่งฟังก์ชัน (หรือ key) เข้าไปตรง ๆ
def sort_by(items, key):
return sorted(items, key=key)
sort_by(users, key=lambda u: u.name) # strategy = lambda💡 จับหลัก: Strategy = "สลับพฤติกรรมได้โดยไม่แก้โค้ดเดิม" — Java เก่าทำผ่าน class, ภาษาใหม่ทำผ่านการส่งฟังก์ชัน เป้าหมายเดียวกัน อย่าติดที่รูปแบบ class
ใน Real World
- Spring
@Componentที่ implement common interface — Spring inject all → Strategy - React
onSubmitprop — ส่งฟังก์ชันจัดการเข้าไป = strategy - Validator chain —
notNull().minLength(5).matches(/regex/)
9. Observer (Pub/Sub) — แจ้ง event
🔤 Observer (ออบ-เซิร์ฟ-เวอร์ = ผู้สังเกต) | Pub/Sub (พับ/ซับ = Publish/Subscribe = ประกาศ/สมัครรับ) — รูปแบบเดียวกันแต่เรียกต่างชื่อในบริบทต่างกัน (Pub/Sub มักหมายถึงผ่าน broker เช่น Kafka, Redis)
ใช้เมื่อ: 1 event ต้องการให้หลายฝั่งรับรู้และทำงานของตัวเอง + ไม่อยากให้ subject ผูกกับ observer อย่าใช้เมื่อ: มีฝั่งเดียวที่สนใจ → callback ตรง ๆ ง่ายกว่า
💡 Modern alternative: ในเคสง่าย — ใช้ functional callback (lambda) แทน Observer class hierarchy → ไม่ต้องมี
interface Observer, แค่รับConsumer<Event>พอ
Observer ให้ object หนึ่ง "แจ้งเตือน" หลาย object เมื่อมีเหตุการณ์ — เช่น order ถูกสร้างแล้ว email/inventory/analytics ต่างรับรู้และทำงานของตัวเอง โดย order ไม่ต้องรู้จักพวกนั้นโดยตรง เป็นรากฐานของ event-driven, DOM events, RxJS และ Spring @EventListener:
java
interface OrderObserver {
void onOrderCreated(Order order);
}
class Order {
private final List<OrderObserver> observers = new ArrayList<>();
public void addObserver(OrderObserver obs) {
observers.add(obs);
}
public void confirm() {
// ...
observers.forEach(o -> o.onOrderCreated(this));
}
}
// Observers
class EmailNotifier implements OrderObserver {
public void onOrderCreated(Order order) {
emailService.send(...);
}
}
class InventoryReducer implements OrderObserver { ... }
class AnalyticsTracker implements OrderObserver { ... }⚠️ ระวัง memory leak:
observers.add(obs)ใน Java/JS ถือ strong reference ไป observer — ถ้า observer ไม่ unsubscribe (removeObserver) ตอนเลิกใช้ → GC เก็บไม่ได้ทำให้ memory ค้าง (โดยเฉพาะ observer ที่อายุสั้น sub กับ subject ที่อยู่ยาว — เช่น UI component listen global event bus)วิธีแก้:
- explicit unsubscribe — observer call
removeObserver()ใน destructor /componentWillUnmount/@PreDestroy- weak reference — เก็บ
List<WeakReference<OrderObserver>>แทน → GC เก็บได้แม้ยังอยู่ใน list (ระวัง: weak ref อาจเป็น null เมื่อใช้ → ต้อง filter)- หรือใช้ library ที่จัดการให้ (Spring
@EventListener, RxJSSubscription.unsubscribe())
Modern — Event-driven
java
// Spring
@EventListener
public void onOrderCreated(OrderCreatedEvent event) { ... }
applicationEventPublisher.publishEvent(new OrderCreatedEvent(order));
@EventListener+ApplicationEventPublisherคือ implementation ของ Observer ที่ Spring จัดการให้ — ดูบท Spring เพื่อรายละเอียด (ที่นี่แสดงรูปแบบเฉย ๆ)
Real World
- DOM events —
element.addEventListener('click', handler) - RxJS Observable
- React
useEffect(subscribe state) - Kafka consumer
- Redis Pub/Sub
10. Command — Encapsulate operation
🔤 Command (คอม-แมนด์ = คำสั่ง) — ห่อ "การกระทำ" เป็น object (action เป็นข้อมูลที่ส่งต่อ/เก็บ/undo ได้)
ใช้เมื่อ: ต้อง queue / undo / log / replay action; CQRS write side; job processor อย่าใช้เมื่อ: action เกิดและจบทันที + ไม่ต้อง undo → method call ปกติพอ
Command ห่อ "การกระทำ" เป็น object — ทำให้เก็บ, ส่งต่อ, queue, undo ได้ (object รู้ทั้งวิธี execute และ undo ตัวเอง) เป็นรากฐานของ undo/redo ใน editor, job queue, และ CQRS (command = write):
java
interface Command {
void execute();
void undo();
}
class CreateUserCommand implements Command {
private final UserService service;
private final CreateUserRequest req;
private Long createdUserId; // ⚠️ mutable state — ดู note ด้านล่าง
public void execute() {
User u = service.create(req);
this.createdUserId = u.getId();
}
public void undo() {
service.delete(createdUserId);
}
}
// Invoker
class CommandHistory {
// ✅ ใช้ Deque/ArrayDeque แทน java.util.Stack (legacy, synchronized, ช้า)
private final Deque<Command> history = new ArrayDeque<>();
public void execute(Command cmd) {
cmd.execute();
history.push(cmd);
}
public void undo() {
if (!history.isEmpty()) history.pop().undo();
}
}📌
java.util.Stackเป็น legacy class (Java 1.0) — extendsVectorซึ่ง synchronize ทุก method (ช้าและ thread-safe แบบไม่จำเป็น) → ใช้Dequeinterface กับ implementationArrayDeque(Java 6+) แทน เร็วกว่าและเป็นแนวทาง modern ที่ Oracle แนะนำเอง (push/pop/peekใช้แบบเดิมได้)
⚠️ immutability concern:
createdUserIdเป็น mutable field — ถ้า command ถูกexecute()2 ครั้ง หรือ thread ขนานกัน → state เพี้ยน (overwrite, race) แนวทางสะอาดกว่า: ทำ Command ให้ immutable + คืนResultobject ที่บรรจุcreatedUserId(เช่นrecord CreateUserResult(Long userId)) → invoker เก็บ result คู่กับ command ไว้ใน history
Real World
- Undo/Redo (text editor, Figma)
- Queue/Job processor
- Saga pattern (microservices) — Command + Compensation
- CQRS — Command = write, Query = read
11. Template Method — Algorithm structure ใน parent
🔤 Template Method (เท็ม-เพลท เม-ธ็อด) — parent กำหนดโครงของ algorithm + subclass override ทีละขั้น
ใช้เมื่อ: หลาย class มีโครงทำงานเหมือนกัน + ต่างกันแค่บางขั้น อย่าใช้เมื่อ: ขั้นตอนยังไม่นิ่ง / ความแตกต่างเยอะ → Strategy (composition) ยืดหยุ่นกว่า
💡 Hollywood Principle: "Don't call us, we'll call you" — Template Method ทำตามหลักนี้: parent (framework) เรียก subclass ตอนเหมาะสม subclass ไม่เรียก parent → เป็นรูปแบบหนึ่งของ Inversion of Control (IoC) ที่เป็นรากฐานของ Spring framework
💡 abstract class = class ที่ instantiate ไม่ได้ (สร้าง
newไม่ได้) มีไว้ให้ extends — มี method ปกติ (มีโค้ด) + abstract method (ไม่มีโค้ด — บังคับ subclass เขียน) ที่นี่DataProcessorกำหนดลำดับในprocess()แล้วบังคับ subclass เขียนread()/validate()/transform()/write()เอง
Template Method กำหนด "โครงของ algorithm" ไว้ใน parent (ลำดับขั้น read→validate→transform→write) แล้วให้ subclass เติมรายละเอียดแต่ละขั้น — ขั้นตอนหลักคงที่ แต่แต่ละแบบทำต่างกันได้ เจอใน framework เยอะ (Spring JdbcTemplate, lifecycle method):
java
abstract class DataProcessor {
// Template method
public final void process() {
Data data = read();
Data validated = validate(data);
Data transformed = transform(validated);
write(transformed);
}
protected abstract Data read();
protected abstract Data validate(Data data);
protected abstract Data transform(Data data);
protected abstract void write(Data data);
}
class CsvProcessor extends DataProcessor {
protected Data read() { /* read csv */ }
protected Data validate(Data data) { /* csv-specific validation */ }
protected Data transform(Data data) { /* csv-specific */ }
protected void write(Data data) { /* write csv */ }
}
class JsonProcessor extends DataProcessor { ... }→ Parent มี algorithm — subclass override step
⚠️ Trade-off
Template Method = inheritance — ตรวจสอบว่า "is-a" จริงไหม
Modern alternative: Strategy (composition)
12. Repository Pattern
java
interface UserRepository {
Optional<User> findById(Long id);
Optional<User> findByEmail(String email);
User save(User user);
void deleteById(Long id);
}
class JpaUserRepository implements UserRepository { ... }
class InMemoryUserRepository implements UserRepository { ... } // for testingข้อดี:
- Domain ไม่รู้ DB
- Test ด้วย in-memory repo
- เปลี่ยน persistence ได้
ใน Spring → extends JpaRepository<User, Long> — auto-generate
13. Specification Pattern
Specification ทำให้ "เงื่อนไขทางธุรกิจ" (active user, อายุ ≥ 18) เป็น object ที่ combine, test, reuse ได้ — แทนที่จะเขียน if ซ้อนกระจาย เอา spec มาต่อด้วย AND/OR เจอใน Spring Data JPA Specification และ validator chain:
java
interface Specification<T> {
boolean isSatisfiedBy(T item);
}
class ActiveUserSpec implements Specification<User> {
public boolean isSatisfiedBy(User u) { return u.isActive(); }
}
class AdultUserSpec implements Specification<User> {
public boolean isSatisfiedBy(User u) { return u.getAge() >= 18; }
}
// Combinator
class AndSpec<T> implements Specification<T> {
private final List<Specification<T>> specs;
@SafeVarargs
public AndSpec(Specification<T>... specs) { // varargs constructor
this.specs = List.of(specs);
}
public boolean isSatisfiedBy(T item) {
return specs.stream().allMatch(s -> s.isSatisfiedBy(item));
}
}
// ใช้
Specification<User> spec = new AndSpec<>(
new ActiveUserSpec(),
new AdultUserSpec()
);
users.stream().filter(spec::isSatisfiedBy).toList();→ Filter logic = first-class object — combine, test, reuse
ใน Real World
- Spring Data JPA Specifications (บทที่ 02 Spring Boot)
- Validator chain
- Predicate ใน Stream
14. Chain of Responsibility
🔤 Chain of Responsibility (เชน ออฟ รี-สปอน-ซิ-บิ-ลิ-ตี้ = ลูกโซ่ความรับผิดชอบ) — handler ต่อกันเป็นลูกโซ่ request วิ่งผ่านทีละตัว
ใช้เมื่อ: มี processing step หลาย step ที่สลับ/เพิ่ม/ลบได้ (เช่น HTTP middleware) อย่าใช้เมื่อ: ขั้นตอนคงที่ + ไม่เปลี่ยน → call ตรง ๆ ง่ายกว่า
Chain of Responsibility ต่อ handler เป็นลูกโซ่ — request วิ่งผ่านทีละตัว (auth → rate limit → validation) แต่ละตัวจัดการส่วนของมันแล้วส่งต่อ ทำให้เพิ่ม/สลับ/ลบ handler ได้ง่าย นี่คือหลักการเบื้องหลัง HTTP middleware และ Servlet/Security FilterChain:
java
abstract class Validator {
private Validator next;
public Validator setNext(Validator next) {
this.next = next;
return next;
}
public void validate(Request req) {
doValidate(req);
if (next != null) next.validate(req);
}
protected abstract void doValidate(Request req);
}
class AuthValidator extends Validator {
protected void doValidate(Request req) {
if (req.getToken() == null) throw new UnauthorizedException();
}
}
class RateLimitValidator extends Validator {
protected void doValidate(Request req) {
if (rateLimiter.exceeded(req.getUserId())) throw new RateLimitException();
}
}
class InputValidator extends Validator {
protected void doValidate(Request req) {
if (req.getBody() == null) throw new ValidationException();
}
}
// ใช้
Validator chain = new AuthValidator();
chain.setNext(new RateLimitValidator()).setNext(new InputValidator());
chain.validate(request);Real World
- HTTP middleware (Express, Spring filter)
- Servlet Filter Chain
- Spring Security FilterChain
15. State Pattern
🔤 State (สเตท = สถานะ) — แต่ละสถานะเป็น class ที่มีพฤติกรรมต่างกัน object เปลี่ยน state = เปลี่ยน behavior
ใช้เมื่อ: object มีพฤติกรรมต่างกันตาม status + transitions ซับซ้อน (state machine) อย่าใช้เมื่อ: status มีแค่ 2-3 ตัว + behavior เปลี่ยนไม่เยอะ → enum ตรง ๆ ง่ายกว่า
เมื่อ object มีพฤติกรรมต่างกันตาม "สถานะ" (order: pending/shipped/delivered) การเขียน if/switch เช็ค status ทุก method จะรก — State pattern แยกแต่ละสถานะเป็น class ที่มีพฤติกรรมของตัวเอง object เปลี่ยนพฤติกรรมโดยเปลี่ยน state object ทำให้ state machine ชัดและเพิ่มสถานะใหม่ง่าย:
java
interface OrderState {
void confirm(OrderContext ctx);
void ship(OrderContext ctx);
void cancel(OrderContext ctx);
}
class PendingState implements OrderState {
public void confirm(OrderContext ctx) { ctx.setState(new ConfirmedState()); }
public void ship(OrderContext ctx) { throw new IllegalStateException("Confirm first"); }
public void cancel(OrderContext ctx) { ctx.setState(new CancelledState()); }
}
class ConfirmedState implements OrderState {
public void confirm(OrderContext ctx) { throw new IllegalStateException("Already confirmed"); }
public void ship(OrderContext ctx) { ctx.setState(new ShippedState()); }
public void cancel(OrderContext ctx) { ctx.setState(new CancelledState()); }
}
// ...
class OrderContext {
private OrderState state = new PendingState();
public void setState(OrderState s) { this.state = s; }
public void confirm() { state.confirm(this); }
public void ship() { state.ship(this); }
public void cancel() { state.cancel(this); }
}ทาง alternative — enum + abstract method (Java feature ที่ enum value override method ได้แต่ละตัว):
java
public enum OrderStatus {
PENDING {
@Override OrderStatus confirm() { return CONFIRMED; }
@Override OrderStatus ship() { throw new IllegalStateException(); }
},
CONFIRMED {
@Override OrderStatus confirm() { throw new IllegalStateException(); }
@Override OrderStatus ship() { return SHIPPED; }
},
SHIPPED { ... };
abstract OrderStatus confirm();
abstract OrderStatus ship();
}💡 Java เอกลักษณ์: enum value แต่ละตัวเหมือน "subclass สั้น ๆ" — เขียน
PENDING { ... }คือ enum value ที่ override abstract methodconfirm()/ship()ของ enum class เอง → ได้ state machine compact ที่ compile-time exhaustive (compiler บังคับให้ enum ทุกตัว implement abstract method)
→ State machine
16. ใน React — Patterns ที่เห็นทุกวัน
ถ้าไม่ได้ใช้ React สามารถข้ามตอนนี้ได้ — เก็บไว้เป็น reference ตอนเข้าบท Frontend / React ภายหลัง
design pattern คลาสสิกไม่ได้อยู่แค่ Java — React ก็เต็มไปด้วยมันแค่เรียกชื่อต่างกัน HOC คือ Decorator, render props คือ Strategy, Context คือ DI, useReducer คือ Command พอเห็นความเชื่อมโยงนี้ก็จะเข้าใจ React ลึกขึ้น:
- Container/Presenter — split logic + view
- HOC (Higher-Order Component) = Decorator (function รับ component → คืน component ใหม่ที่ทำ behavior เพิ่ม)
- Render Props = Strategy (ส่ง render function เป็น prop → component ใช้ function นั้น render)
- Hooks = Composition + Strategy + Custom hooks
- Context = Singleton + Dependency Injection
- Reducer = Command (action → state transition)
- Compound Component = Builder ใน UI
React 2024-2026 — patterns ใหม่ที่ควรรู้
- Server Components (Next.js App Router default) — render บน server, ส่ง HTML + serialized props ลง client → data อยู่ใกล้แหล่งกำเนิด ลด client bundle
- Server Actions — function ทำ mutation บน server เรียกจาก client เหมือน RPC (
'use server') — ลด API boilerplate usehook (React 19) — รับ promise/context ใน component แล้ว Suspense รอให้เสร็จ → data fetching แบบใหม่ที่เลิกพึ่งuseEffectสำหรับ async
17. ⚠️ Anti-patterns: Pattern Overuse
java
// ❌ Pattern soup
class UserManagerFactoryProviderSingletonBuilder { ... }→ Pattern ที่ดีที่สุด = pattern ที่จำเป็น + อ่านง่าย
กฎ Pattern
- 🌟 รู้จัก pattern → recognize เมื่อเจอ
- 🌟 ใช้เมื่อ problem ตรงกับ pattern
- ❌ อย่าไป force pattern กับ code ที่ไม่ต้องการ
- ❌ ไม่ใช่ tool ที่ใช้ทำให้ "ดูเทพ"
18. Pattern ที่ไม่ค่อยได้ใช้ (อ่านพอ)
- Prototype — clone object
- Bridge — แยก abstraction กับ implementation
- Flyweight — share state ระหว่าง object เล็ก ๆ
- Memento — snapshot state
- Visitor — operation บน hierarchy
- Iterator — sequential access (built-in ในภาษาส่วนใหญ่)
- Mediator — coordinate communication
- Interpreter — language parser
→ รู้ว่ามี + อ่านเมื่อเจอ — อย่าท่อง
19. ตัวอย่างจริง — Payment System
ปิดท้ายด้วยเคสจริงที่รวมหลาย pattern เข้าด้วยกัน — payment system ที่ใช้ Strategy (เลือก processor), Factory (สร้าง), Decorator (เพิ่ม logging/retry) ฯลฯ ในระบบจริง pattern ไม่ได้ใช้เดี่ยว ๆ แต่ประกอบกันเพื่อแก้ปัญหาที่ซับซ้อน:
ใช้หลาย pattern พร้อมกัน:
java
// 1. Strategy — payment processor
interface PaymentProcessor {
PaymentResult charge(BigDecimal amount, PaymentMethod method);
}
// 2. Factory — create processor by type (pure factory — ไม่ cache ซ้ำกับ Spring container)
@Component
class PaymentProcessorFactory {
private final PaymentConfig config;
public PaymentProcessorFactory(PaymentConfig config) {
this.config = config;
}
public PaymentProcessor create(String type) {
return switch (type) {
case "STRIPE" -> new StripeProcessor(config);
case "PAYPAL" -> new PayPalProcessor(config);
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}
// 💡 ถ้า processor เป็น Spring bean อยู่แล้ว → Spring container เก็บ singleton ให้
// ไม่ต้อง cache ใน factory อีก (double-cache สับสน)
// 3. Decorator — add retry, logging
class LoggingPaymentProcessor implements PaymentProcessor {
private final PaymentProcessor inner;
public PaymentResult charge(BigDecimal amount, PaymentMethod method) {
log.info("Charging {} via {}", amount, inner);
long start = System.currentTimeMillis();
try {
PaymentResult result = inner.charge(amount, method);
log.info("Charged in {}ms: {}", System.currentTimeMillis() - start, result);
return result;
} catch (Exception e) {
log.error("Charge failed", e);
throw e;
}
}
}
// 4. Observer — notify on payment events
@EventListener
public void onPaymentSuccess(PaymentSucceededEvent event) {
// Send email, update analytics, ...
}
// 5. Facade — checkout flow
@Service
class CheckoutFacade {
private final PaymentProcessorFactory factory;
public OrderConfirmation checkout(Order order, PaymentMethod method) {
PaymentProcessor processor = factory.create(order.getPaymentType());
PaymentResult result = processor.charge(order.total(), method);
// ...
}
}
// 6. Repository — persistence
interface OrderRepository {
Order save(Order order);
}20. ⚠️ Common Pitfalls
| ❌ | ✅ |
|---|---|
| Force pattern ตอนยังไม่มี problem | wait for pattern → 3rd time refactor |
| Singleton everywhere | DI + Spring container |
| Inheritance for code reuse | Composition + Strategy |
*Manager, *Helper, *Util class | Service + domain methods |
| 23 pattern memorize | รู้จัก top 10 + recognize |
| Pattern ที่ทำให้ code อ่านยากขึ้น | wrong pattern — choose simpler |
21. Checkpoint
🛠️ Checkpoint 3.1 — Spot Patterns
อ่าน source code ของ Spring framework / open source — list pattern ที่เห็น (อย่างน้อย 5)
🛠️ Checkpoint 3.2 — Refactor with Strategy
java
class Compressor {
public byte[] compress(String type, byte[] data) {
if (type.equals("GZIP")) { /* gzip */ }
else if (type.equals("ZIP")) { /* zip */ }
else if (type.equals("LZ4")) { /* lz4 */ }
}
}Refactor with Strategy
🛠️ Checkpoint 3.3 — Build Notification System
- Multiple channels (email, SMS, push) — Strategy
- Add logging + retry to each — Decorator
- Send to multiple channels per user pref — Observer
- One service to coordinate — Facade
🛠️ Checkpoint 3.4 — State Machine
ทำ BlogPost state: DRAFT → REVIEW → PUBLISHED → ARCHIVED
- ใช้ enum + abstract method หรือ State pattern
- Action: submit, approve, reject, publish, archive
22. สรุปบท
✅ Pattern = recurring solution — vocabulary สำหรับ communicate
✅ Strategy ⭐ — ใช้บ่อยที่สุด (= OCP)
✅ Factory + Builder — สร้าง object ที่ flexible
✅ Decorator — add behavior โดยไม่แก้ class เดิม
✅ Facade — interface เดียวซ่อน sub-system
✅ Observer — event-driven, pub/sub
✅ Repository — abstract data access (Spring Data)
✅ State — state machine ที่ explicit
✅ Singleton = ระวัง — ใช้ DI container แทน
✅ Pattern ใน framework: Spring, React = SOLID + Patterns ฝังลึก
✅ อย่า force pattern — wait for pattern emerge
23. Glossary — คำศัพท์ + คำอ่าน
23 GoF patterns
| คำศัพท์ | คำอ่าน | ความหมาย |
|---|---|---|
| Singleton | ซิง-เกิ้ล-ตัน | แบบเดี่ยว — instance เดียวทั้ง app |
| Factory | แฟค-โท-รี่ | โรงงาน — สร้าง object โดยไม่ระบุ class |
| Abstract Factory | แอ๊บ-สแตร็คท์ แฟค-โท-รี่ | โรงงานของโรงงาน — สร้างตระกูล object |
| Builder | บิ้ล-เดอร์ | ผู้สร้างทีละขั้น |
| Prototype | โพร-โท-ไทป์ | ต้นแบบ — clone object |
| Adapter | อะ-แด๊พ-เตอร์ | หัวแปลง — แปลง interface |
| Bridge | บริดจ์ | สะพาน — แยก abstraction กับ implementation |
| Composite | คอม-โพ-สิท | โครงสร้างต้นไม้ — รวม object เป็นกลุ่ม |
| Decorator | เด-คอ-เร-เตอร์ | ตัวประดับ/ห่อ — เพิ่ม behavior |
| Facade | ฟา-ซ้าด | ด้านหน้า — interface เดียวซ่อน sub-system |
| Flyweight | ฟลาย-เวท | น้ำหนักเบา — แชร์ state |
| Proxy | พร็อก-ซี่ | ตัวแทน |
| Chain of Responsibility | เชน ออฟ รี-สปอน-ซิ-บิ-ลิ-ตี้ | ลูกโซ่ความรับผิดชอบ |
| Command | คอม-แมนด์ | คำสั่ง — encapsulate action |
| Interpreter | อิน-เทอร์-พรี-เตอร์ | ตัวตีความ |
| Iterator | อิ-เท-เรเตอร์ | ตัววนซ้ำ |
| Mediator | มี-เดีย-เตอร์ | ผู้ประสานงานกลาง |
| Memento | เม-เม็น-โต้ | บันทึก/snapshot |
| Observer | ออบ-เซิร์ฟ-เวอร์ | ผู้สังเกต/ติดตาม |
| State | สเตท | สถานะ |
| Strategy | สแตร-ทิ-จี้ | กลยุทธ์ — สลับ algorithm |
| Template Method | เท็ม-เพลท เม-ธ็อด | โครงวิธีการใน parent |
| Visitor | วิ-ซิ-เตอร์ | ผู้เยี่ยม — operation ข้าม class |
ศัพท์อื่นในบท
| คำศัพท์ | คำอ่าน | ความหมาย |
|---|---|---|
| Creational | ครี-เอ-ชั่น-แนล | (หมวด) เกี่ยวกับการสร้าง object |
| Structural | สตรัค-เจอ-รัล | (หมวด) เกี่ยวกับโครงสร้าง |
| Behavioral | บี-เฮฟ-วิ-เออ-รัล | (หมวด) เกี่ยวกับพฤติกรรม/interaction |
| GoF | จี-โอ-เอฟ (Gang of Four) | แก๊งสี่คนผู้เขียนหนังสือ Design Patterns 1994 |
| Pub/Sub | พับ-ซับ | Publish/Subscribe = ประกาศ/สมัครรับ |
| telescoping constructor | เทเลส-โค-ปิ้ง คอน-สตรัค-เตอร์ | constructor หลายตัวที่ยาวขึ้นเรื่อย ๆ |
| Law of Demeter | ลอว์ ออฟ ดี-มี-เทอร์ | "อย่าคุยกับคนแปลกหน้า" — คุยกับเพื่อนใกล้ตัวเท่านั้น |
| Hollywood Principle | ฮอลลีวูด พริน-ซิ-เปิ้ล | "Don't call us, we'll call you" = IoC |
| Inversion of Control (IoC) | อิน-เวอร์-ชั่น ออฟ คอน-โทรล | กลับด้านการควบคุม — framework เรียกเรา ไม่ใช่เราเรียก framework |
| Dependency Injection (DI) | ดี-เพ็น-เด็น-ซี่ อิน-เจ๊ค-ชั่น | ฉีด dependency เข้าจากภายนอก แทนสร้างเอง |
| immutable | อิม-มิว-ทะ-เบิ้ล | เปลี่ยนค่าไม่ได้หลังสร้าง |
| weak reference | วีค เร-เฟอ-เร็นซ์ | reference ที่ GC เก็บได้แม้ยังถืออยู่ |
| BigDecimal | บิ๊ก-เด-ซี่-มอล | type สำหรับเลขทศนิยมที่แม่นยำ ใช้กับเงิน |