Chương 7 — Factory Method Pattern

Factory method pattern — kiến trúc và hai biến thể

Hai biến thể của factory method pattern

Key idea 1: Classic Gang of Four Factory Method

Trong biến thể gốc, mỗi class cụ thể có factory riêng của nó:

Instance (interface)
├── ConcreteInstanceA
└── ConcreteInstanceB

IFactory (interface)
├── ConcreteFactoryA → tạo ConcreteInstanceA
└── ConcreteFactoryB → tạo ConcreteInstanceB

Cách dùng:

# Để lấy concreteinstancea:
factory_a = ConcreteFactoryA()
instance_a = factory_a.create_instance()  # Trả về ConcreteInstanceA qua interface

# Để lấy concreteinstanceb:
factory_b = ConcreteFactoryB()
instance_b = factory_b.create_instance()  # Trả về ConcreteInstanceB qua interface

Nhược điểm: Mỗi loại instance cần một factory class riêng — tăng số lượng class.

Key idea 2: Simple Factory Method (Parameterized) — Được Khuyến Nghị

Một factory duy nhất xử lý tất cả loại instance thông qua tham số:

Instance (interface)
├── ConcreteInstanceA
└── ConcreteInstanceB

InstanceFactory (static methods only)
└── create_instance(name) → trả về Instance theo tên

Cách dùng:

instance_a = InstanceFactory.create_instance("instance_a")
instance_b = InstanceFactory.create_instance("instance_b")

Ưu điểm:

  • Chỉ cần một factory class cho tất cả các loại.
  • Dễ mở rộng bằng cách thêm case mới trong factory.
  • Code client đơn giản hơn nhiều.

Thiết kế factory method pattern

Key idea 3: Các bước thiết kế

Bước 1: Xác định nhóm object cần factory. Ví dụ: Shape, Bullet, Vehicle.

Bước 2: Tạo interface/abstract class cho nhóm đó. Tất cả class con phải tuân theo contract này.

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def draw(self):
        pass

Bước 3: Tạo factory với static method nhận parameter xác định loại instance.

class ShapeFactory:
    @staticmethod
    def create_shape(shape_type: str, **kwargs) -> Shape:
        if shape_type == "circle":
            return Circle(**kwargs)
        elif shape_type == "rectangle":
            return Rectangle(**kwargs)
        raise ValueError(f"Unknown shape: {shape_type}")

Bước 4: Sử dụng Enum thay vì string thô để tránh lỗi typo.

from enum import Enum, auto

class ShapeType(Enum):
    CIRCLE = auto()
    RECTANGLE = auto()

class ShapeFactory:
    @staticmethod
    def create_shape(shape_type: ShapeType, **kwargs) -> Shape:
        if shape_type == ShapeType.CIRCLE:
            return Circle(**kwargs)
        elif shape_type == ShapeType.RECTANGLE:
            return Rectangle(**kwargs)

Key idea 4: Context class để truyền dữ liệu

Thay vì truyền nhiều tham số rời rạc, dùng một context class bao gồm tất cả:

class ShapeContext:
    def __init__(self, x, y, color, size=None):
        self.x = x
        self.y = y
        self.color = color
        self.size = size

class ShapeFactory:
    @staticmethod
    def create_shape(shape_type: ShapeType, context: ShapeContext) -> Shape:
        if shape_type == ShapeType.CIRCLE:
            return Circle(context)
        elif shape_type == ShapeType.RECTANGLE:
            return Rectangle(context)

Lợi ích: Nếu sau này cần thêm tham số mới, chỉ cần thêm vào ShapeContext — method signature không cần thay đổi.

Đăng ký nhận Newsletter
Cập nhật bài viết mới nhất!