iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 11

[Day 11] 讓介面更簡單 – 門面模式 (Facade Pattern)

  • 分享至 

  • xImage
  •  

門面模式 (Facade Pattern)

  • Facade Pattern(外觀模式)
    • 是一種結構型設計模式,為一個子系統裡面的一組 Interface 提供一個統一的介面。門面定義了更高階的 Interface,可以讓子系統更容易使用。 (或者說白話一點,可以讓使用者不需要知道太多子系統細節,就能使用套裝指令來達成原本的目標)
      https://ithelp.ithome.com.tw/upload/images/20230923/20138643iEKIKPQbCy.png
  • 特性
    • 簡化接口: 將多個複雜的子系統接口集成為一個簡單的接口
    • 解耦合: 客戶端與子系統之間的依賴性降低
    • 可維護性: 改變子系統的內部實作不會影響到使用外觀模式的客戶端
  • 應用場景
    • 當一個系統的子組件具有複雜的接口和依賴時
    • 為遠程或第三方API提供一個統一的接口
    • 當需要簡化和解釋一個非常複雜的算法或業務邏輯
  • 分析
    • 優點
      • 簡化客戶端代碼
      • 提高系統的模塊化
      • 更易於控制子系統的變動
    • 缺點
      • 可能會增加子系統的數量和複雜性
      • 如果不正確使用,可能會隱藏子系統的功能和靈活性

[補充] 最少知識原則 (Least Knowledge Principle / Law of Demeter)

只與最接近的朋友交談
(深入淺出設計模式 2nd (p.267)

  • 原則
    • 局部交互: 一個對象應該只與其直接關聯的對象進行交互
    • 有限知識: 一個對象不應該具有超過其需求的信息或複雜性
    • 降低耦合: 通過局部交互有限知識來降低各個對象之間的耦合度
  • 方針: 在任何物件的方法裡,你都只能呼叫屬於這些東西的方法
    • 該物件本身
    • 用參數傳給該方法的物件
    • 該方法建立的或實例化的任何物件
    • 該物件的任何組件 (可以將「組件」想成被實例變數參考的任何物件。HAS-A 關係)

這些方針告訴我們,如果我們呼叫其他的方法而收到一個物件,不要直接對著那個物件呼叫它的方法
(深入淺出設計模式 2nd (p.268)

經典範例 (家庭劇院系統)

在一個完整的家庭劇院系統中,通常會有多個組件如放大器(Amplifier)、調諧器(Tuner)、串流播放器(StreamingPlayer)、投影機(Projector)、燈光(TheaterLights)、螢幕(Screen)、光碟機 (Popper)...等。這些組件各自有不同的操作和設定,對一般使用者 (Client)來說,可能會感到操作複雜和不便。因此,我們可以使用 Facade Pattern 來簡化這一系列複雜的操作

// 放大器
class Amplifier {
public:
    void on() { std::cout << "Amplifier is ON.\n"; }
    void off() { std::cout << "Amplifier is OFF.\n"; }
};

// 調諧器
class Tuner {
public:
    void setFrequency(double f) { std::cout << "Tuner set to frequency " << f << ".\n"; }
};

// 串流播放器
class StreamingPlayer {
public:
    void play(std::string movie) { std::cout << "StreamingPlayer playing " << movie << ".\n"; }
    void stop() { std::cout << "StreamingPlayer stopped.\n"; }
};

// 投影機
class Projector {
public:
    void on() { std::cout << "Projector is ON.\n"; }
    void off() { std::cout << "Projector is OFF.\n"; }
};

// 劇院燈光
class TheaterLights {
public:
    void dim() { std::cout << "Theater lights are dimming.\n"; }
};

// 屏幕
class Screen {
public:
    void down() { std::cout << "Screen is down.\n"; }
    void up() { std::cout << "Screen is up.\n"; }
};

// 光碟機
class Popper {
public:
    void on() { std::cout << "Popper is ON.\n"; }
    void off() { std::cout << "Popper is OFF.\n"; }
};




// Home Theater Facade (簡化給使用者操作的介面)
class HomeTheaterFacade {
private:
    Amplifier amp;
    Tuner tuner;
    StreamingPlayer player;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    Popper popper;
public:
    void watchMovie(std::string movie) {
        std::cout << "Preparing to watch movie...\n";
        popper.on();
        lights.dim();
        screen.down();
        amp.on();
        tuner.setFrequency(101.9);
        projector.on();
        player.play(movie);
    }

    void endMovie() {
        std::cout << "Shutting down theater...\n";
        player.stop();
        projector.off();
        screen.up();
        lights.dim();
        amp.off();
        popper.off();
    }
};

// 使用者看電影範例
int main() {
    HomeTheaterFacade homeTheater;
    homeTheater.watchMovie("The Matrix");
    homeTheater.endMovie();
}

Reference

[1]. https://refactoring.guru/design-patterns/facade
[2]. https://ithelp.ithome.com.tw/articles/10227186


上一篇
[Day 10] 物件導向轉接器 - 轉接器模式 (Adapter Pattern)
下一篇
[Day 12] 回顧比較 — Decorator / Adapter / Facade 三種 Design Patterns
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言