#แนวคิด

Abstract Factory เป็น Creational Design Pattern สำหรับสร้างชุดออบเจ็กต์ที่เกี่ยวข้องกัน (family of related products) โดยไม่ต้องระบุคลาสที่เป็นรูปธรรมในโค้ดฝั่งผู้ใช้งาน เหมาะเมื่อระบบต้องสลับชุดผลิตภัณฑ์ เช่น UI แบบ Windows และ macOS โดยยังคงใช้ API เดียวกัน

#โครงสร้าง

  • Abstract Products: Button, Checkbox กำหนดพฤติกรรมร่วม
  • Concrete Products: WindowsButton, MacButton, WindowsCheckbox, MacCheckbox
  • Abstract Factory: GUIFactory กำหนดเมธอดสร้างผลิตภัณฑ์
  • Concrete Factories: WindowsFactory, MacFactory สร้างผลิตภัณฑ์ที่เข้าชุดกัน
  • Client: Application ใช้งานผ่าน interface โดยไม่ผูกกับคลาสจริง
classDiagram
    class GUIFactory {
      <<interface>>
      +createButton() Button
      +createCheckbox() Checkbox
    }
    class WindowsFactory
    class MacFactory
    GUIFactory <|.. WindowsFactory
    GUIFactory <|.. MacFactory
    class Button { <<interface>> +render() void }
    class Checkbox { <<interface>> +render() void }
    class WindowsButton
    class MacButton
    class WindowsCheckbox
    class MacCheckbox
    Button <|.. WindowsButton
    Button <|.. MacButton
    Checkbox <|.. WindowsCheckbox
    Checkbox <|.. MacCheckbox
    WindowsFactory ..> WindowsButton : creates
    WindowsFactory ..> WindowsCheckbox : creates
    MacFactory ..> MacButton : creates
    MacFactory ..> MacCheckbox : creates

#Workshop: สร้าง UI Components ข้ามแพลตฟอร์ม

ใช้ Java 17+ สร้างไฟล์ Main.java:

interface Button {
    void render();
}

interface Checkbox {
    void render();
}

class WindowsButton implements Button {
    public void render() {
        System.out.println("Render Windows button");
    }
}

class MacButton implements Button {
    public void render() {
        System.out.println("Render macOS button");
    }
}

class WindowsCheckbox implements Checkbox {
    public void render() {
        System.out.println("Render Windows checkbox");
    }
}

class MacCheckbox implements Checkbox {
    public void render() {
        System.out.println("Render macOS checkbox");
    }
}

interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }

    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }

    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

class Application {
    private final Button button;
    private final Checkbox checkbox;

    Application(GUIFactory factory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }

    void render() {
        button.render();
        checkbox.render();
    }
}

public class Main {
    public static void main(String[] args) {
        String platform = args.length > 0 ? args[0] : "windows";
        GUIFactory factory = switch (platform.toLowerCase()) {
            case "windows" -> new WindowsFactory();
            case "mac" -> new MacFactory();
            default -> throw new IllegalArgumentException("Unsupported platform: " + platform);
        };
        new Application(factory).render();
    }
}

#ทดลองรัน

javac Main.java
java Main windows
# Render Windows button
# Render Windows checkbox

java Main mac
# Render macOS button
# Render macOS checkbox

#เปรียบเทียบกับ Factory Method

ประเด็น Factory Method Abstract Factory
จุดประสงค์ กำหนดจุดสร้างผลิตภัณฑ์ผ่านเมธอด สร้างชุดผลิตภัณฑ์ที่สัมพันธ์กัน
รูปแบบ มักใช้ inheritance เพื่อเปลี่ยนชนิดผลิตภัณฑ์ มักใช้ composition ผ่าน factory interface
ตัวอย่าง สร้างปุ่มชนิดหนึ่ง สร้างปุ่มและ checkbox ให้เข้าธีมเดียวกัน

#ข้อดีและข้อควรระวัง

ข้อดี: ลดการผูกติดกับคลาสจริง, สลับ family ได้ง่าย, ป้องกันการผสมผลิตภัณฑ์ต่างชุดโดยไม่ตั้งใจ, สนับสนุน Dependency Inversion Principle

ข้อควรระวัง: เพิ่ม interface และคลาสจำนวนมาก และหากเพิ่มชนิดผลิตภัณฑ์ใหม่ เช่น Slider ต้องแก้ factory interface และ concrete factories ทุกตัว

#แนวทางต่อยอด

  • เพิ่ม LinuxFactory พร้อมผลิตภัณฑ์ LinuxButton และ LinuxCheckbox
  • เขียน JUnit 5 tests ตรวจสอบว่าแต่ละ factory คืนผลิตภัณฑ์ถูก family
  • เชื่อม factory กับ dependency injection เพื่อเลือกแพลตฟอร์มจาก configuration

#สรุป

Abstract Factory เหมาะเมื่อแอปพลิเคชันต้องสร้าง หลายผลิตภัณฑ์ที่ต้องเข้าชุดกัน และต้องการแยกโค้ดธุรกิจออกจากรายละเอียดการสร้างออบเจ็กต์ แต่ถ้าสร้างเพียงผลิตภัณฑ์ชนิดเดียว Factory Method หรือ simple factory อาจเรียบง่ายกว่า