Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

Problem

Giả sử ta đang xây dựng một ứng dụng phân tích dữ liệu nhận vào ba định dạng là DOC, CSV và PDF. Mỗi định dạng sẽ có một lớp tương ứng chịu trách nhiệm xử lý và phân tích.

Có thể thấy, ngoài các đoạn code xử lý định dạng dữ liệu thì các đoạn code còn lại ở ba lớp là như nhau. Điều này gây ra sự trùng lặp code ở trong ứng dụng.

Solution

Để giải quyết vấn đề này, ta có thể xây dựng một template method chứa các bước cần thiết để phân tích dữ liệu. Mỗi bước có thể được ghi đè bởi các lớp dẫn xuất.

Structure

Cấu trúc của template method pattern sẽ gồm những thành phần sau:

  • Abstract class: định nghĩa các bước cần để thực hiện tác vụ và một template method gọi sử dụng các bước đó.
  • Concrete class: là các lớp có chứa các phương thức ghi đè các phương thức của abstract class.

Minh họa:

Implementation

Giả sử ta cần xây dựng một trang web có ba trang: home page, detail page và contact page.

Một layout của trang web thông thường sẽ bao gồm header, navigation bar, body và footer. Phần body ở mỗi trang sẽ khác nhau và các phần còn lại thường ít bị thay đổi.

Ta có thể sử dụng template method pattern để render ra giao diện của trang web với phần body có nội dung linh hoạt và giảm thiểu sự trùng lặp code khi render các phần khác.

Abstract Class

Xây dựng abstract class như sau:

class PageTemplate {
protected:
	void showHeader() {
		std::cout << "<header>\n";
	}
 
	void showNavigation() {
		std::cout << "<navigation>\n";
	}
 
	void showFooter() {
		std::cout << "<footer>\n";
	}
 
	virtual void showBody() = 0;
 
public:
	void showPage() {
		showHeader();
		showNavigation();
		showBody();
		showFooter();
	}
};

Phân tích:

  • Các phương thức cần để thực hiện việc render trang web: showHeader, showNavigation, showBodyshowFooter. Riêng phương thức showBody là một phương thức thuần ảo và cho phép override.
  • Template method: showPage gọi sử dụng các phương thức trên.

Concrete Class

Các concrete class sẽ override lại phương thức showBody của abstract class:

class HomePage : public PageTemplate {
protected:
	void showBody(){
		std::cout << "Content of the home page\n";
	}
};
 
class DetailPage : public PageTemplate {
protected:
	void showBody() {
		std::cout << "Content of the detail page\n";
	}
};
 
class ContactPage : public PageTemplate {
protected:
	void showBody() {
		std::cout << "Content of the contact page\n";
	}
};

Usage

Gọi sử dụng như sau:

void TestTemplateMethod() {
	PageTemplate* homePage = new HomePage();
	homePage->showPage();
	std::cout << "---\n";
 
	PageTemplate* detailPage = new DetailPage();
	detailPage->showPage();
	std::cout << "---\n";
 
	PageTemplate* contactPage = new ContactPage();
	contactPage->showPage();
	std::cout << "---\n";
}

Output:

<header>
<navigation>
Content of the home page
<footer>
---
<header>
<navigation>
Content of the detail page
<footer>
---
<header>
<navigation>
Content of the contact page
<footer>
---

Applicability

Sử dụng template method pattern khi:

  • Ta muốn client có thể mở rộng một số bước cụ thể của thuật toán nhưng không phải toàn bộ thuật toán.
  • Ta có một vài class có những thuật toán tương tự nhau.

Pros and Cons

ProsCons
Cho phép client có thể ghi đè một số phần của thuật toán lớn hơnCó thể vi phạm nguyên lý Liskov substitution khi ghi đè một bước mặc định thông qua các lớp con
Đem các đoạn code bị trùng lặp vào bên trong một superclassKhó bảo trì khi template method có nhiều bước

Resources