C++ 設計模式 - 樣板方法模式 Template Method Pattern

在資料分析領域中,我們需要從海量的資料中提取有價值的資訊。但是面對不同格式的資料,例如:XML、CSV、JSON 等格式,我們該如何設計一個靈活又高效的分析工具呢?然而不論資料格式種類不同,分析的步驟通常是相似的,今天讓我們一起來探討設計模式中的樣板方法模式 Template Method Pattern ,看看它如何幫助我們解決這個問題。

什麼是樣板方法模式?

樣板方法模式是一種行為設計模式,它在一個方法中定義了一個演算法的骨架,而將一些通用步驟的實作延遲到子類中。樣板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟的內容。換句話說,樣板方法確保了演算法的骨架(例如流程的步驟)是一致的,但細節部分可以由不同的子類自行定義。

聽起來有點抽象?別擔心,讓我們用一個生活中的例子來解釋。

想像你在煮一鍋湯。無論你煮的是什麼湯,基本步驟都是相似的:

  1. 準備食材
  2. 加水並煮沸
  3. 加入主要食材
  4. 調味
  5. 盛盤

這個流程就是一個「樣板方法」。不同的湯可能在食材準備和調味方式上有所不同,但整體流程是一致的。

樣板方法模式資料分析工具的應用

回到資料分析的情景,假設我們正在開發一個資料分析工具,這個工具可以讀取不同格式的資料(XML、CSV、JSON),並產生分析報告。無論資料來源為何,我們的分析流程大致相同,包括讀取資料、分析資料、生成報告。

我們可以定義一個 DataAnalyzer 基類,來統一處理通用的分析步驟,但將具體的資料讀取方式交給子類別來實作。

首先,定義 DataAnalyzer 基類,其中包含了樣板方法 analyze()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class DataAnalyzer {
public:
void analyze() {
readData();
processData();
generateReport();
}
virtual ~DataAnalyzer() = default;

protected:
virtual void readData() = 0; // 抽象方法,由子類別實作
void processData() {
std::cout << "Processing data..." << std::endl;
// 通用的資料處理邏輯
}
void generateReport() {
std::cout << "Generating report..." << std::endl;
// 通用的報告生成邏輯
}
};

接著,我們可以為每種資料格式建立不同的子類別,並各自實作 readData() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class XMLDataAnalyzer : public DataAnalyzer {
protected:
void readData() override {
std::cout << "Reading data from XML file..." << std::endl;
// 具體的 XML 資料讀取邏輯
}
};

class CSVDataAnalyzer : public DataAnalyzer {
protected:
void readData() override {
std::cout << "Reading data from CSV file..." << std::endl;
// 具體的 CSV 資料讀取邏輯
}
};

class JSONDataAnalyzer : public DataAnalyzer {
protected:
void readData() override {
std::cout << "Reading data from JSON file..." << std::endl;
// 具體的 JSON 資料讀取邏輯
}
};

當我們使用這些子類別時,無需擔心具體的資料讀取邏輯,只需關注分析流程的整體結構,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void ClientCode(std::unique_ptr<DataAnalyzer> analyzer) {
// ...
analyzer->analyze();
// ...
}

int main() {
std::unique_ptr<XMLDataAnalyzer> xmlAnalyzer = std::make_unique<XMLDataAnalyzer>();
ClientCode(std::move(xmlAnalyzer)); // 分析 XML 資料

std::unique_ptr<DataAnalyzer> csvAnalyzer = std::make_unique<CSVDataAnalyzer>();
ClientCode(std::move(csvAnalyzer)); // 分析 CSV 資料

ClientCode(std::make_unique<JSONDataAnalyzer>()); // 分析 JSON 資料

return 0;
}

執行上述程式碼,我們會得到以下輸出:

1
2
3
4
5
6
7
8
9
Reading data from XML file...
Processing data...
Generating report...
Reading data from CSV file...
Processing data...
Generating report...
Reading data from JSON file...
Processing data...
Generating report...

在這個範例中,我們展示了如何使用樣板方法模式來處理不同資料格式的分析流程。透過定義通用的分析步驟,我們確保了分析邏輯的一致性,同時又保留了靈活性,讓我們可以根據實際不同需求來實作對應的資料讀取方式。

樣板方法模式的優點

樣板方法模式的優點如下,主要優勢在於統一流程和靈活擴展,

  • 程式碼複用性:將通用的分析步驟寫在基類中,避免了在每個子類別中重複寫相同的邏輯。
  • 靈活與擴展性:可以輕鬆添加新的資料格式,只需建立新的子類別並實現對應的讀取方法,而不需要改變整體的分析流程。
  • 容易維護:分析流程的改動只需修改基類,而不需要修改每個子類別,這使得系統更加易於維護。

總結

樣板方法模式在軟體開發中,就像是一個烹飪配方,固定的步驟確保了整體的流程不會亂套,而細節上的變化則由各種料理的需求來決定。這樣的設計不僅讓程式更具結構性,也讓開發者能夠輕鬆地應對需求的變更或擴展。如果你在日常的開發工作中需要處理類似的問題,不妨考慮使用樣板方法模式來優雅地解決。