#Factory Method คืออะไร

Factory Method เป็น Creational Design Pattern ที่กำหนดเมธอดสำหรับสร้างออบเจ็กต์ไว้ในคลาสแม่ (Creator) แต่เปิดโอกาสให้คลาสลูก (Concrete Creator) ตัดสินใจว่าจะสร้างออบเจ็กต์ชนิดใด โดยโค้ดที่เรียกใช้งานพึ่งพา interface ของผลิตภัณฑ์ (Product) แทนคลาสจริง

จุดสำคัญ: Factory Method ใช้ inheritance และ polymorphism เพื่อเปลี่ยนชนิดของออบเจ็กต์ที่สร้าง ต่างจาก Simple Factory ซึ่งมักใช้เมธอดเดียวพร้อม switch เลือกชนิด

#โครงสร้าง

classDiagram
    class Notification {
        <<interface>>
        +send(String message) void
    }
    class EmailNotification {
        +send(String message) void
    }
    class SmsNotification {
        +send(String message) void
    }
    class NotificationCreator {
        <<abstract>>
        +notifyUser(String message) void
        #createNotification() Notification
    }
    class EmailNotificationCreator {
        #createNotification() Notification
    }
    class SmsNotificationCreator {
        #createNotification() Notification
    }
    Notification <|.. EmailNotification
    Notification <|.. SmsNotification
    NotificationCreator <|-- EmailNotificationCreator
    NotificationCreator <|-- SmsNotificationCreator
    NotificationCreator ..> Notification : creates / uses

#Workshop: ระบบแจ้งเตือน Email และ SMS

ตัวอย่างนี้ใช้ Java 17+ และแยกคลาสเป็นไฟล์เพื่อให้เห็นความรับผิดชอบชัดเจน

#1. Product interface

Notification.java

public interface Notification {
    void send(String message);
}

#2. Concrete Products

EmailNotification.java

public class EmailNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("EMAIL: " + message);
    }
}

SmsNotification.java

public class SmsNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("SMS: " + message);
    }
}

#3. Abstract Creator

NotificationCreator.java

public abstract class NotificationCreator {
    // Factory Method: subclasses decide the concrete product.
    protected abstract Notification createNotification();

    public void notifyUser(String message) {
        Notification notification = createNotification();
        notification.send(message);
    }
}

#4. Concrete Creators

EmailNotificationCreator.java

public class EmailNotificationCreator extends NotificationCreator {
    @Override
    protected Notification createNotification() {
        return new EmailNotification();
    }
}

SmsNotificationCreator.java

public class SmsNotificationCreator extends NotificationCreator {
    @Override
    protected Notification createNotification() {
        return new SmsNotification();
    }
}

#5. Client

Main.java

public class Main {
    public static void main(String[] args) {
        NotificationCreator creator = new EmailNotificationCreator();
        creator.notifyUser("Your order has shipped");

        creator = new SmsNotificationCreator();
        creator.notifyUser("Your OTP is 123456");
    }
}

#6. รันโปรแกรม

วางไฟล์ .java ทั้งหมดไว้ในไดเรกทอรีเดียวกัน แล้วรัน

javac *.java
java Main

ผลลัพธ์

EMAIL: Your order has shipped
SMS: Your OTP is 123456

#ลำดับการทำงาน

sequenceDiagram
    participant Client
    participant Creator as EmailNotificationCreator
    participant Product as EmailNotification
    Client->>Creator: notifyUser("Hello")
    Creator->>Creator: createNotification()
    Creator->>Product: new EmailNotification()
    Creator->>Product: send("Hello")
    Product-->>Client: Output: EMAIL: Hello

#ข้อดีและข้อจำกัด

ข้อดี ข้อจำกัด
ลดการผูกติดกับคลาสผลิตภัณฑ์จริง จำนวนคลาสเพิ่มขึ้น
เพิ่มชนิดผลิตภัณฑ์ได้โดยสร้าง Concrete Creator ใหม่ อาจซับซ้อนเกินไปสำหรับระบบขนาดเล็ก
สนับสนุน Open/Closed Principle การเลือก Creator ที่ runtime ยังต้องมีองค์ประกอบจัดการ
รวมขั้นตอนการใช้งานผลิตภัณฑ์ไว้ใน Creator ไม่ได้กำจัด new ออกจากระบบทั้งหมด

#Factory Method vs Simple Factory vs Abstract Factory

Pattern แนวคิดหลัก
Simple Factory เมธอด/คลาสกลางเลือกสร้างผลิตภัณฑ์ตามพารามิเตอร์ (ไม่ใช่หนึ่งใน GoF 23 patterns)
Factory Method ให้ subclass override เมธอดเพื่อเลือกผลิตภัณฑ์หนึ่งประเภท
Abstract Factory interface สำหรับสร้างชุดผลิตภัณฑ์ที่สัมพันธ์กัน โดยไม่ระบุคลาสจริง

#ควรใช้เมื่อใด

เหมาะเมื่อโค้ดส่วนกลางต้องทำงานกับผลิตภัณฑ์ผ่าน interface เดียวกัน แต่ต้องเปิดให้ subclass กำหนดชนิดผลิตภัณฑ์ เช่น ตัวส่งข้อความ ตัวอ่านไฟล์ หรือไดรเวอร์จัดเก็บข้อมูล หากเพียงเลือกชนิดด้วยเงื่อนไขไม่กี่กรณีและไม่มีความจำเป็นต้องขยายด้วย subclass การใช้ Simple Factory หรือ dependency injection อาจตรงไปตรงมากว่า

#แบบฝึกหัดต่อยอด

  1. เพิ่ม PushNotification และ PushNotificationCreator โดยไม่แก้ไข NotificationCreator.
  2. เขียน JUnit 5 test เพื่อทดสอบว่า Creator แต่ละชนิดส่งข้อความได้ถูกต้อง โดยใช้ test double แทนการพิมพ์ลง console.
  3. เปลี่ยนตัวอย่างให้ส่ง NotificationResult และจัดการข้อผิดพลาดจากผู้ให้บริการภายนอก.

#สรุป

Factory Method แยก การสร้างออบเจ็กต์ ออกจาก กระบวนการใช้งานออบเจ็กต์ ผ่าน abstract Creator และ Concrete Creator ทำให้เพิ่มผลิตภัณฑ์ชนิดใหม่ได้โดยลดผลกระทบต่อโค้ดหลัก แต่ควรเลือกใช้ให้เหมาะกับความซับซ้อนของระบบ