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

Template Method Pattern (Mẫu Template Method)

Định nghĩa (Definition)

Template Method định nghĩa khung của thuật toán (Skeleton of an Algorithm) trong một method, trì hoãn một số bước cho subclass. Nó cho subclass định nghĩa lại (Redefine) một số bước mà không thay đổi cấu trúc thuật toán.

Ví dụ Coffee Shop

Mọi đồ uống nóng theo cùng quy trình: xay hạt → pha → rót vào ly → thêm phụ gia (Condiment). Nhưng mỗi loại đồ uống tùy chỉnh các bước cụ thể — espresso dùng xay mịn và không thêm phụ gia, còn latte dùng xay trung bình và thêm sữa nóng.

Cấu trúc (Structure)

Abstract Class — Khung thuật toán (Algorithm Skeleton)

public abstract class BeverageMaker
{
// Template Method — định nghĩa khung thuật toán
public void Prepare()
{
GrindBeans();
Brew();
PourInCup();
if (CustomerWantsCondiments())
AddCondiments();
Console.WriteLine();
}

protected abstract void GrindBeans();
protected abstract void Brew();
protected abstract void AddCondiments();

protected virtual void PourInCup() =>
Console.WriteLine(" Rót vào ly...");

// Hook — override tùy chọn (có hành vi mặc định)
protected virtual bool CustomerWantsCondiments() => true;
}

Concrete Class — Tùy chỉnh từng bước

public class EspressoMaker : BeverageMaker
{
protected override void GrindBeans() =>
Console.WriteLine(" Xay 18g hạt espresso mịn");

protected override void Brew() =>
Console.WriteLine(" Chiết xuất ở 9 bar trong 25 giây");

protected override void AddCondiments() =>
Console.WriteLine(" Phục vụ nguyên chất — không phụ gia");

protected override bool CustomerWantsCondiments() => false;
}

public class LatteMaker : BeverageMaker
{
protected override void GrindBeans() =>
Console.WriteLine(" Xay 18g hạt espresso trung bình");

protected override void Brew() =>
Console.WriteLine(" Rút double espresso shot");

protected override void AddCondiments() =>
Console.WriteLine(" Thêm sữa nóng (microfoam mịn)");
}

Client

var makers = new BeverageMaker[] { new EspressoMaker(), new LatteMaker() };

foreach (var maker in makers)
{
Console.WriteLine($"Chuẩn bị {maker.GetType().Name.Replace("Maker", "")}:");
maker.Prepare();
}
mẹo

EspressoMaker override hook CustomerWantsCondiments() trả về false. Thuật toán bỏ qua AddCondiments(). Đây là hook — method có hành vi mặc định mà subclass có thể override tùy chọn.

Các loại method trong Template Method

LoạiMục đíchModifier
Template MethodĐịnh nghĩa khung thuật toánpublic sealed
Abstract methodPhải được override bởi subclassprotected abstract
Concrete methodHành vi dùng chung (default implementation)protected virtual
HookOverride tùy chọn với hành vi mặc địnhprotected virtual trả bool

Nguyên tắc Hollywood (Hollywood Principle)

"Don't call us, we'll call you."

Base class gọi method của subclass, không phải ngược lại. Template method kiểm soát luồng — subclass cung cấp chi tiết implementation.

Template Method vs Strategy

Template MethodStrategy
Cơ chếInheritanceComposition
Khi nào chọnCấu trúc thuật toán cố định, bước thay đổiToàn bộ thuật toán thay đổi
Thay đổi runtimeKhông (cố định lúc compile)Có (inject strategy khác)

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

  • StreamRead()/Write() là template method; subclass override ReadByte()/WriteByte()
  • ASP.NET Core ControllerBase — lifecycle method như OnActionExecuting()
  • BackgroundServiceExecuteAsync() là template method với khung đã cung cấp
  • Test fixture — SetUp()/TearDown() trong unit test framework

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

  • Có cấu trúc thuật toán cố định với bước thay đổi
  • Hành vi chung giữa subclass nên nằm ở một nơi
  • Muốn kiểm soát extension point (Hollywood Principle)

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

  • Thuật toán thay đổi hoàn toàn — dùng Strategy
  • Ít bước chung — overhead inheritance không đáng
  • Cần thay đổi hành vi lúc runtime — Strategy tốt hơn

Điểm chính (Key Takeaways)

  • Template Method định nghĩa khung thuật toán trong base class
  • Subclass override bước cụ thể mà không thay đổi cấu trúc tổng thể
  • Hook cung cấp điểm tùy chỉnh tùy chọn với hành vi mặc định
  • Dùng inheritance — nếu prefer composition, dùng Strategy

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

Q: Tại sao đánh dấu template method là sealed? Để ngăn subclass thay đổi cấu trúc thuật toán. Mục đích là base class kiểm soát luồng. Nếu subclass override được template method itself, guarantee bị mất.

Q: Template Method khác polymorphism thông thường như thế nào? Template Method là cách dùng polymorphism cụ thể. Polymorphism thông thường là subclass override method. Template Method thêm thứ tự gọi cố định — base class gọi nhiều abstract/virtual method theo thứ tự cụ thể. Cấu trúc là đổi mới chính.

Q: "Hook" trong Template Method là gì? Hook là method có default implementation mà subclass có thể override tùy chọn. Nó không abstract — cung cấp default hợp lý. Ví dụ: CustomerWantsCondiments() mặc định trả true, nhưng EspressoMaker override trả false.

  • Strategy — thay thế dựa trên composition
  • Builder — tương tự từng bước, nhưng cho construction
  • Factory Method — pattern khác cũng dùng inheritance hook