Chuyển tới nội dung chính

Factory Method Pattern (Mẫu Factory Method)

Định nghĩa (Definition)

Factory Method định nghĩa một interface để tạo đối tượng, nhưng cho phép subclass quyết định class nào sẽ được khởi tạo. Phương thức này trì hoãn việc khởi tạo (Defer Instantiation) cho các class dẫn xuất, tách biệt client code khỏi concrete type.

Ví dụ Coffee Shop

Một quán cà phê nhận đơn từ nhiều kênh khác nhau — khách đến trực tiếp (Walk-in), ứng dụng di động (Mobile App), và drive-through. Mỗi kênh tạo cà phê khác nhau (kích cỡ mặc định, extras khác nhau), nhưng quy trình đặt hàng là giống nhau.

Cấu trúc (Structure)

Triển khai (Implementation)

// The Creator abstract class (Lớp Creator trừu tượng)
public abstract class CoffeeOrderBase
{
// Factory Method — subclass quyết định tạo cái gì
public abstract Coffee CreateCoffee();

// Template method — logic dùng chung sử dụng factory method
public string PlaceOrder()
{
var coffee = CreateCoffee();
return $"Order placed: {coffee}";
}
}

// Concrete Creators — mỗi cái tạo một loại cà phê khác nhau
public class WalkInOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Espresso();
}

public class MobileAppOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Latte { Size = CupSize.Large };
}

public class DriveThroughOrder : CoffeeOrderBase
{
public override Coffee CreateCoffee() => new Cappuccino();
}

// Usage
CoffeeOrderBase order = new MobileAppOrder();
Console.WriteLine(order.PlaceOrder());
// Output: Order placed: Latte (Large) — $4.00 [Espresso Shot, Steamed Milk]

Với tham số — Chọn loại cà phê lúc runtime

public enum CoffeeType { Espresso, Latte, Cappuccino }

public class SmartCoffeeOrder : CoffeeOrderBase
{
private readonly CoffeeType _type;
private readonly CupSize _size;

public SmartCoffeeOrder(CoffeeType type, CupSize size = CupSize.Medium)
{
_type = type;
_size = size;
}

public override Coffee CreateCoffee() => _type switch
{
CoffeeType.Espresso => new Espresso { Size = _size },
CoffeeType.Latte => new Latte { Size = _size },
CoffeeType.Cappuccino => new Cappuccino { Size = _size },
_ => throw new ArgumentException($"Unknown coffee type: {_type}")
};
}

// Usage
var order = new SmartCoffeeOrder(CoffeeType.Latte, CupSize.Large);
Console.WriteLine(order.PlaceOrder());
// Output: Order placed: Latte (Large) — $4.00 [Espresso Shot, Steamed Milk]

Simple Factory (Không phải mẫu GoF, nhưng phổ biến)

Simple Factory là một class duy nhất với một method tạo đối tượng dựa trên tham số. Đây không phải mẫu GoF chính thức nhưng được sử dụng rộng rãi khi không cần sự linh hoạt dựa trên subclass.

public static class CoffeeFactory
{
public static Coffee Create(CoffeeType type, CupSize size = CupSize.Medium) => type switch
{
CoffeeType.Espresso => new Espresso { Size = size },
CoffeeType.Latte => new Latte { Size = size },
CoffeeType.Cappuccino => new Cappuccino { Size = size },
_ => throw new ArgumentException($"Unknown coffee type: {type}")
};
}

// Usage
var coffee = CoffeeFactory.Create(CoffeeType.Espresso, CupSize.Small);
Simple Factory vs Factory Method

Simple Factory — một class, một method, dựa trên tham số. Đơn giản hơn, đủ dùng cho hầu hết trường hợp. Factory Method — dựa trên kế thừa (Inheritance), subclass override việc tạo. Tốt hơn khi logic tạo khác nhau tùy ngữ cảnh.

Sử dụng thực tế trong .NET (.NET Real-World Usage)

  • IHttpMessageHandlerFactory.CreateHandler() — tạo HTTP handler
  • DbProviderFactory.CreateConnection() — tạo DB connection cho các provider khác nhau
  • TaskFactory.StartNew() — tạo và lên lịch task
  • Activator.CreateInstance() — khởi tạo kiểu lúc runtime

Khi nào sử dụng (When to Use)

  • Class không thể dự đoán trước đối tượng nào cần tạo
  • Muốn ủy quyền khởi tạo cho subclass
  • Cần tách biệt client code khỏi concrete product class
  • Đang xây dựng framework nơi người dùng cắm (Plug-in) implementation của họ

Khi nào KHÔNG sử dụng (When NOT to Use)

  • Khi chỉ có một loại sản phẩm — constructor đơn giản là đủ
  • Khi logic khởi tạo đơn giản — đừng thêm factory chỉ cho new Foo()
  • Khi cần họ sản phẩm liên quan (Families of Related Products) — dùng Abstract Factory

Điểm chính (Key Takeaways)

  • Factory Method là về trì hoãn khởi tạo cho subclass — base class không biết concrete product nào sẽ nhận được
  • Client (base class) làm việc với abstract product interface — tách biệt khỏi concrete type
  • Nguyên tắc Open/Closed (OCP): thêm loại sản phẩm mới bằng cách thêm creator subclass mới, không cần sửa code hiện có
  • Simple Factory thường là đủ — chỉ dùng mẫu GoF khi cần sự linh hoạt dựa trên subclass

Câu hỏi phỏng vấn (Interview Questions)

Q: Khác biệt giữa Simple Factory và Factory Method là gì? Simple Factory là một class duy nhất với switch/if — tập trung hóa. Factory Method dùng kế thừa (Inheritance) — mỗi subclass override phương thức tạo.

Q: Factory Method liên quan đến Open/Closed Principle như thế nào? Loại sản phẩm mới được thêm bằng cách tạo creator subclass mới. Code hiện có không bao giờ thay đổi — nó chỉ gọi factory method trừu tượng.

Q: Khi nào dùng Factory Method thay vì Abstract Factory? Factory Method tạo một loại sản phẩm. Abstract Factory tạo họ sản phẩm liên quan. Dùng Factory Method khi chỉ cần một sản phẩm.