Strategy Pattern:我是個有策略的人
2026年8月11日 下午2:02 · 閱讀 2 分鐘
系列文章: 常用設計模式整理 (第 3 篇)
生活例子:今天想怎麼去公司 / 學校
每天出門上班或上課,總是要挑選個合適的通勤方式。平時習慣走路或騎車,天氣糟糕時可能適合搭捷運,但睡過頭的話可能就得叫輛計程車。另外過去大學校園裡甚至還多了個「電動滑板車」的選項。各種策略皆有其適用情境,但無論何者,目的都是「抵達公司 / 教室」。
當發現一個目標有各種達成方式可選擇時,不妨就考慮試試 Strategy Pattern 吧。
系統需求:支援多種儲存平台的應用程式
- 用戶可透過環境設定,選擇要從哪個平台上傳/下載檔案
- 目前支援用戶本地的電腦硬碟,以及 Google Cloud
- 未來應用程式希望繼續新增選項,吸引更多用戶
可以想想在應用設計模式前,自己會怎麼設計此系統
系統實作
實作:制定統一的存取介面
- 存取平台都必須有上傳與下載兩個功能
public interface StoragePlatform {
void upload(String filePath);
void download(String fileName);
}#include <iostream>
#include <string>
using namespace std;
class StoragePlatform {
public:
virtual void upload(const string& filePath) = 0;
virtual void download(const string& fileName) = 0;
virtual ~StoragePlatform() = default;
};from abc import ABC, abstractmethod
class StoragePlatform(ABC):
@abstractmethod
def upload(self, file_path: str):
pass
@abstractmethod
def download(self, file_name: str):
pass實作:將支援的存取平台逐一寫成類別
- 目前支援本地硬碟以及 Google 雲端儲存
- 未來要加入新選擇,只要撰寫新的 class 就好(SOLID: Open-Closed Principle)
public class LocalDiskStorage implements StoragePlatform {
@Override
public void upload(String filePath) {
// 實作細節...
System.out.println("上傳檔案至本機硬碟:" + filePath);
}
@Override
public void download(String fileName) {
// 實作細節...
System.out.println("從本機硬碟下載檔案:" + fileName);
}
}
public class GoogleCloudStorage implements StoragePlatform {
@Override
public void upload(String filePath) {
// 實作細節...
System.out.println("上傳檔案至 Google Cloud:" + filePath);
}
@Override
public void download(String fileName) {
// 實作細節...
System.out.println("從 Google Cloud 下載檔案:" + fileName);
}
}#include <iostream>
#include <string>
using namespace std;
class LocalDiskStorage : public StoragePlatform {
public:
void upload(const string& filePath) override {
// 實作細節...
cout << "上傳檔案至本機硬碟:" << filePath << endl;
}
void download(const string& fileName) override {
// 實作細節...
cout << "從本機硬碟下載檔案:" << fileName << endl;
}
};
class GoogleCloudStorage : public StoragePlatform {
public:
void upload(const string& filePath) override {
// 實作細節...
cout << "上傳檔案至 Google Cloud:" << filePath << endl;
}
void download(const string& fileName) override {
// 實作細節...
cout << "從 Google Cloud 下載檔案:" << fileName << endl;
}
};class LocalDiskStorage(StoragePlatform):
def upload(self, file_path: str):
# 實作細節...
print(f"上傳檔案至本機硬碟:{file_path}")
def download(self, file_name: str):
# 實作細節...
print(f"從本機硬碟下載檔案:{file_name}")
class GoogleCloudStorage(StoragePlatform):
def upload(self, file_path: str):
# 實作細節...
print(f"上傳檔案至 Google Cloud:{file_path}")
def download(self, file_name: str):
# 實作細節...
print(f"從 Google Cloud 下載檔案:{file_name}")實作:呼叫端只需要與介面溝通
- 檔案管理系統直接與介面互動,不用管也看不到實作
public class FileService {
private StoragePlatform storagePlatform;
public FileService(StoragePlatform storagePlatform) {
this.storagePlatform = storagePlatform;
}
public void upload(String filePath) {
storagePlatform.upload(filePath);
}
public void download(String fileName) {
storagePlatform.download(fileName);
}
}- 檔案管理系統直接與介面互動,不用管也看不到實作
shared_ptr為 smart pointer,可避免手動進行delete的麻煩
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class FileService {
private:
shared_ptr<StoragePlatform> storagePlatform;
public:
FileService(shared_ptr<StoragePlatform> storagePlatform)
: storagePlatform(storagePlatform) {}
void upload(const string& filePath) {
storagePlatform->upload(filePath);
}
void download(const string& fileName) {
storagePlatform->download(fileName);
}
};- 檔案管理系統直接與介面互動,不用管也看不到實作
class FileService:
def __init__(self, storage_platform: StoragePlatform):
self.storage_platform = storage_platform
def upload(self, file_path: str):
self.storage_platform.upload(file_path)
def download(self, file_name: str):
self.storage_platform.download(file_name)實作:使用者自行決定要採取什麼策略
- 每次 App 啟動時,依據使用者設定的環境變數來決定使用的儲存平台
public class Main {
public static void main(String[] args) {
String platform = System.getenv("STORAGE_PLATFORM"); // "local" or "gcs"
StoragePlatform storagePlatform = "gcs".equals(platform)
? new GoogleCloudStorage()
: new LocalDiskStorage();
FileService fileService = new FileService(storagePlatform);
fileService.upload("report.pdf");
fileService.download("report.pdf");
}
}- 每次 App 啟動時,依據使用者設定的環境變數來決定使用的儲存平台
- Assign 物件給
shared_ptr指標時,則配合make_shared創建物件
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
using namespace std;
int main() {
const char* env = getenv("STORAGE_PLATFORM");
string platform = env ? env : "";
shared_ptr<StoragePlatform> storagePlatform;
if (platform == "gcs") {
storagePlatform = make_shared<GoogleCloudStorage>();
} else {
storagePlatform = make_shared<LocalDiskStorage>();
}
FileService fileService(storagePlatform);
fileService.upload("report.pdf");
fileService.download("report.pdf");
return 0;
}- 每次 App 啟動時,依據使用者設定的環境變數來決定使用的儲存平台
import os
if __name__ == "__main__":
platform = os.environ.get("STORAGE_PLATFORM")
storage_platform = GoogleCloudStorage() if platform == "gcs" else LocalDiskStorage()
file_service = FileService(storage_platform)
file_service.upload("report.pdf")
file_service.download("report.pdf")系統類別圖 Class Diagram
設計模式簡要分析
- Encapsulation:將演算法實作細節封裝至類別內
- Abstraction:外部只要與介面溝通,與策略實作解耦
- 方便擴充:未來若要加入新演算法,只要撰寫新的類別就好
此區塊為個人主觀的重點,也可以自己透過 OOP 四大支柱 或 SOLID 設計原則 進行更深入地分析
參考資料
Strategy Design Pattern — GeeksforGeeks
SOLID Design Principles