外觀模式為子系統中的一群介面提供一個一致的高層介面,讓子系統更容易使用。生活譬喻:早期看電視只需開電視,現代需開電視、機頂盒、音響、切換訊號源……外觀模式就是那個「萬用遙控器」,一鍵搞定所有步驟。
外觀模式:提供一個統一介面,封裝子系統的一組介面,降低客戶端與子系統的耦合度。
核心價值:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Client │────▶│ Facade │────▶│SubsystemA│
└──────────┘ └──────────┘ └──────────┘
│ ┌──────────┐ ┌──────────┐
├───────────▶│SubsystemB│
│ └──────────┘ └──────────┘
▼
┌──────────┐
│SubsystemC│
└──────────┘
#include <iostream>
#include <memory>
#include <string>
// 子系統類別(無共同基類)
class Amplifier {
public:
void On() { std::cout << "功放開機\n"; }
void SetVolume(int v) { std::cout << "音量設為 " << v << "\n"; }
void Off() { std::cout << "功放關機\n"; }
};
class Tuner {
public:
void On() { std::cout << "調諧器開機\n"; }
void SetFrequency(double f) { std::cout << "頻率 " << f << " MHz\n"; }
void Off() { std::cout << "調諧器關機\n"; }
};
class DvdPlayer {
public:
void On() { std::cout << "DVD 開機\n"; }
void Play(const std::string& movie) { std::cout << "播放電影: " << movie << "\n"; }
void Stop() { std::cout << "DVD 停止\n"; }
void Off() { std::cout << "DVD 關機\n"; }
};
class Projector {
public:
void On() { std::cout << "投影機開機\n"; }
void WideScreenMode() { std::cout << "寬螢幕模式\n"; }
void Off() { std::cout << "投影機關機\n"; }
};
class Lights {
public:
void Dim(int level) { std::cout << "燈光調暗至 " << level << "%\n"; }
void On() { std::cout << "燈光全開\n"; }
};
class Screen {
public:
void Down() { std::cout << "螢幕降下\n"; }
void Up() { std::cout << "螢幕收起\n"; }
};
class PopcornPopper {
public:
void On() { std::cout << "爆米花機開機\n"; }
void Pop() { std::cout << "開始爆米花!\n"; }
void Off() { std::cout << "爆米花機關機\n"; }
};
// 外觀類別:簡化客戶端操作
class HomeTheaterFacade {
public:
HomeTheaterFacade(Amplifier* amp, Tuner* tuner, DvdPlayer* dvd,
Projector* projector, Lights* lights, Screen* screen,
PopcornPopper* popper)
: amp_(amp), tuner_(tuner), dvd_(dvd), projector_(projector),
lights_(lights), screen_(screen), popper_(popper) {}
void WatchMovie(const std::string& movie) {
std::cout << "=== 準備看電影 ===\n";
popper_->On(); popper_->Pop();
lights_->Dim(10);
screen_->Down();
projector_->On(); projector_->WideScreenMode();
amp_->On(); amp_->SetVolume(5);
dvd_->On(); dvd_->Play(movie);
std::cout << "=== 享受電影中 ===\n";
}
void EndMovie() {
std::cout << "=== 結束觀影 ===\n";
popper_->Off();
lights_->On();
screen_->Up();
projector_->Off();
amp_->Off();
dvd_->Stop(); dvd_->Off();
std::cout << "=== 系統關閉 ===\n";
}
private:
Amplifier* amp_;
Tuner* tuner_;
DvdPlayer* dvd_;
Projector* projector_;
Lights* lights_;
Screen* screen_;
PopcornPopper* popper_;
};
// 客戶端
int main() {
// 建立子系統實例
Amplifier amp; Tuner tuner; DvdPlayer dvd;
Projector projector; Lights lights; Screen screen; PopcornPopper popper;
// 外觀封裝複雜初始化
HomeTheaterFacade theater(&, &tuner, &dvd, &projector,
&lights, &screen, &popper);
// 客戶端極簡呼叫
theater.WatchMovie("星際效應");
theater.EndMovie();
return 0;
}
| 模式 | 意圖 | 關係 |
|---|---|---|
| 外觀 | 提供簡化介面 | 封裝子系統,單向依賴 |
| 中介者 | 協調物件互動 | 雙向依賴,行為邏輯集中 |
| 抽象工廠 | 建立相關物件族 | 專注建構,非操作封裝 |
SpringApplication.run()、QApplication 建構StringBuilder、ProcessBuilder外觀模式是「為複雜系統設計一個好用的介面」的藝術。它不引入新功能,而是重新組織既有功能,降低使用門檻。記住:好的外觀像萬用遙控器,壞的外觀像萬用膠水——前者簡化操作,後者混淆職責。實務中,外觀常與依賴注入、模組化架構結合,作為微服務邊界或框架進入點。