C++ 設計模式 - 策略模式 Strategy Pattern

在日常開發中,我們常需要對檔案進行壓縮,而不同的壓縮格式(如 Zip、Rar、7z 等)各有其優缺點。有時候我們希望能夠根據當下需求自由地切換壓縮方式,而不需要改動太多的程式碼。這時候策略模式 Strategy Pattern 就可以幫我們輕鬆實現這個需求。

什麼是策略模式?

策略模式是一種行為設計模式,它可以讓我們定義一系列的演算法,將每個演算法封裝起來,並讓它們可以互相替換使用。這樣一來程式碼不僅更加靈活,也更容易擴展跟維護了。

簡單來說,策略模式就是讓程式可以隨意更換的「策略」,讓程式能夠靈活地應對不同種的情況。

策略模式在壓縮器中的應用

假設你正在開發一個檔案壓縮的功能。一開始你可能只支援 ZIP 格式壓縮。但隨著使用者需求的增加,你發現需要添加 RAR、7Z 等其他壓縮格式的支援。

你的程式碼可能會寫成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Compressor {
public:
void compress(const std::string& filename, const std::string& format) {
if (format == "zip") {
// ZIP 壓縮邏輯
} else if (format == "rar") {
// RAR 壓縮邏輯
} else if (format == "7z") {
// 7Z 壓縮邏輯
} else {
throw std::runtime_error("不支援的格式");
}
}
};

這種方法的問題在於每次新增新的壓縮格式時,都需要修改 Compressor 類別。這違反了「開放封閉原則」,也就是軟體應該對擴展開放,對修改封閉。

讓我們看看如何使用策略模式來改進這個設計:

我們先定義一個壓縮策略介面 CompressionStrategy,

1
2
3
4
5
class CompressionStrategy {
public:
virtual void compress(const std::string& filename) = 0;
virtual ~CompressionStrategy() = default;
};

然後為每種壓縮格式實作具體的策略,分別為 ZipStrategy、RarStrategy、SevenZipStrategy,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ZipStrategy : public CompressionStrategy {
public:
void compress(const std::string& filename) override {
std::cout << "使用 ZIP 壓縮 " << filename << " 檔案\n";
}
};

class RarStrategy : public CompressionStrategy {
public:
void compress(const std::string& filename) override {
std::cout << "使用 RAR 壓縮 " << filename << " 檔案\n";
}
};

class SevenZipStrategy : public CompressionStrategy {
public:
void compress(const std::string& filename) override {
std::cout << "使用 7Z 壓縮 " << filename << " 檔案\n";
}
};

根據此情境在設計時,建立一個 Compressor 壓縮器,又為稱上下文類別,這個 Compressor 類別可以根據需求動態選擇不同的壓縮策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Compressor {
private:
std::unique_ptr<CompressionStrategy> strategy;

public:
Compressor(std::unique_ptr<CompressionStrategy> strategy)
: strategy(std::move(strategy)) {}

void setStrategy(std::unique_ptr<CompressionStrategy> newStrategy) {
strategy = std::move(newStrategy);
}

void compress(const std::string& filename) {
strategy->compress(filename);
}
};

當需要使用壓縮器時,可以這樣寫,Compressor 將會執行已經選擇的壓縮策略進行壓縮,然後也可以執行期間更換壓縮策略,

1
2
3
4
5
6
7
8
9
int main() {
Compressor compressor(std::make_unique<ZipStrategy>());
compressor.compress("file1.txt"); // 輸出:使用 ZIP 壓縮 file1.txt 檔案

compressor.setStrategy(std::make_unique<SevenZipStrategy>());
compressor.compress("file2.txt"); // 輸出:使用 7Z 壓縮 file2.txt 檔案

return 0;
}

策略模式的優點

使用策略模式,讓我們能夠方便地擴展壓縮器的功能,當需要增加新的壓縮格式時,只需新增一個實作了 CompressionStrategy 介面,並將其設定到 Compressor 中即可,完全不需要修改現有 Compressor 與其它壓縮策略的程式碼。另外策略模式還能讓程式碼變得更加清晰易懂,避免大量的條件判斷或分支邏輯,使系統在面對複雜業務需求時,依然能保持穩定和易於維護。

總結

策略模式是一個很實用的設計模式,能夠有效解決系統中某些功能需要頻繁變動或擴展的問題。在這個壓縮器範例中,我們看到如何使用策略模式來靈活地切換壓縮格式,並保持程式碼的清晰和可維護性。並能在日後的開發中靈活運用它,讓你的程式碼更加優雅。