Facade 外觀模式簡介與 C# 範例【結構型5】【設計模式來了_10】

2023-10-24 21:00:47

〇、簡介

1、什麼是外觀模式?

一句話解釋:

  將一系列需要一起進行的操作,封裝到一個類中,通過對某一個方法的呼叫,自動完成一系列操作。

外觀模式是一種簡單而又實用的設計模式,它的目的是提供一個統一的介面,使得使用者端可以通過這個介面來存取子系統中的一組介面,而無需關心子系統中介面的具體實現。外觀模式將子系統中的介面封裝在一個外觀類中,使得子系統的內部細節對使用者端隱藏起來。

官方意圖描述:為子系統中的一組介面提供一個一致的介面,Facade 模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。

一個比喻:(課表與調休日)

  加入今天是週六需要補國慶放假週一的課,那麼只需要公告一下,今天按週一的課表上課就行了,不需要逐一通知課表上的任課老師。此時‘週一的課’就是一個封裝後的方法,調了這個方法後,就無需再呼叫每節課的任課老師,課表會進行一一對應。

2、外觀模式的優缺點和適用場景

優點:

  • 提供了一個統一的介面:外觀模式提供了一個統一的介面,使得使用者端可以通過這個介面來存取子系統中的一組介面,而無需關心子系統中介面的具體實現。這樣可以使得程式碼更容易理解和維護。
  • 隱藏子系統的複雜性:外觀類將子系統的功能封裝起來,使用者端只需要呼叫外觀類的方法即可完成操作,從而隱藏了子系統的複雜性。
  • 提高了程式碼的可延伸性:外觀模式提供了一個統一的介面,使得使用者端可以通過這個介面來存取子系統中的一組介面,而無需關心子系統中介面的具體實現。這樣可以使得程式碼更容易擴充套件,當需要新增新的子系統時,只需要新增一個新的外觀類即可。

缺點:

  • 增加了系統的複雜性:外觀模式引入了外觀類和子系統之間的依賴關係,使得系統的結構和實現變得更加複雜。
  • 如果設計不當,增加新的子系統可能需要修改外觀類的原始碼,違背了開閉原則:因此,在設計外觀類時,需要考慮到將來可能會增加新的子系統,使得外觀類的原始碼可以容易地擴充套件。
  • 可能增加系統的耦合度:外觀類和子系統之間的依賴關係可能會導致系統的耦合度增加,從而影響系統的可維護性和可測試性。
  • 可能降低系統的靈活性:由於外觀類將子系統的功能封裝起來,因此可能會限制使用者端對子系統的客製化和擴充套件。

適用場景:

  • 子系統複雜:當子系統的呼叫介面非常複雜時,可以使用外觀模式來簡化使用者端與子系統之間的互動。
  • 層次複雜:當系統結構層次複雜時,每個層級都一個使用外觀物件作為該層入口,可以簡化層次間的呼叫介面。
  • 需要隱藏子系統的細節:當子系統的實現細節不應該被使用者端直接存取時,可以使用外觀模式來隱藏這些細節。
  • 需要降低耦合度:當用戶端和子系統之間的耦合度太高時,可以使用外觀模式來降低它們之間的耦合度。

一、外觀模式的程式碼實現

下面是一個關於家庭影院HomeTheaterFacade的範例程式碼,假設整個影院由四部分(媒體播放器、低音炮、揚聲器、遙控)組成,然後通過家庭影院類,將子系統的開關整合到一起,最終實現一鍵播放和關機:

// 測試一下
class Program
{
    static void Main(string[] args)
    {
        HomeTheaterFacade homeTheaterFacade=new HomeTheaterFacade();
        homeTheaterFacade.PlayMovie();
        homeTheaterFacade.StopMovie();
        Console.ReadLine();
    }
}
public class HomeTheaterFacade // 家庭影院外觀
{
    private MediaPlayer mp; // 媒體播放機
    private Subwoofer subwoofer; // 低音炮
    private Amplifier amplifier; // 揚聲器
    private RemoteControl remoteControl; // 無線遙控
    public HomeTheaterFacade()
    {
        mp = new MediaPlayer();
        subwoofer = new Subwoofer();
        amplifier = new Amplifier();
        remoteControl = new RemoteControl();
    }
    public void PlayMovie()
    {
        mp.Open();
        subwoofer.PowerOn();
        amplifier.PowerOn();
        remoteControl.Play();
    }
    public void StopMovie()
    {
        remoteControl.Stop();
        amplifier.PowerOff();
        subwoofer.PowerOff();
        mp.Close();
    }
}
public class MediaPlayer
{
    public void Open()
    {
        Console.WriteLine("Opening the movie...");
    }
    public void Close()
    {
        Console.WriteLine("Closing the movie...");
    }
}
public class Subwoofer
{
    public void PowerOn()
    {
        Console.WriteLine("Powering on the subwoofer...");
    }
    public void PowerOff()
    {
        Console.WriteLine("Powering off the subwoofer...");
    }
}
public class Amplifier
{
    public void PowerOn()
    {
        Console.WriteLine("Powering on the amplifier...");
    }
    public void PowerOff()
    {
        Console.WriteLine("Powering off the amplifier...");
    }
}
public class RemoteControl
{
    public void Play()
    {
        Console.WriteLine("Playing the movie...");
    }
    public void Stop()
    {
        Console.WriteLine("Stopping the movie...");
    }
}

後續如果又想新增燈光效果,那可以再新增一個類,然後把開關也加在PlayMovie()StopMovie()兩方法中即可。

二、結構

由上一章節的程式碼可類比出外觀模式的結構:

Facade(HomeTheaterFacade):

  Facade 知道哪些子系統類負責處理請求,還可將客戶的請求代理給適當的子系統物件。

SubsystemClasses 子系統類(MediaPlayer、Subwoofer、Amplifier、RemoteControl):

  包含子系統功能實現;處理由 Facade 物件指派的任務;沒有 Facade 的任何相關資訊,即沒有指向 Facade 的指標。

三、相關模式

Abstract Factory 模式可以與 Facade 模式一起使用以提供一個介面,這一介面可用來以一種子系統獨立的方式建立子系統物件。Abstract Factory 也可以代替 Facade 模式隱藏那些與平臺相關的類。

Mediator 模式與 Facade 模式的相似之處是,它抽象了一些已有的類的功能。然而,Mediator 的目的是對同類之間的任意通訊進行抽象,通常集中不屬於任何單個物件的功能。Mediator 的同類物件知道中介者並與它通訊,而不是直接與其他同類物件通訊。相對而言 Facade 模式僅對子系統物件的介面進行抽象,從而使它們更容易使用;它並不定義新功能,子系統也不知道 Facade 的存在。

通常來講,僅需要一個 Facade 物件,因此 Facade 物件通常屬於 Singleton 模式。