C#設計模式(11)——外觀模式(Facade Pattern)


一、引言

在軟件開發過程中,客戶端程序經常會與復雜系統的內部子系統進行耦合,從而導致客戶端程序隨着子系統的變化而變化,然而為了將復雜系統的內部子系統與客戶端之間的依賴解耦,從而就有了外觀模式,也稱作 ”門面“模式。下面就具體介紹下外觀模式。

二、外觀模式的詳細介紹

2.1 定義

外觀模式提供了一個統一的接口,用來訪問子系統中的一群接口。外觀定義了一個高層接口,讓子系統更容易使用。使用外觀模式時,我們創建了一個統一的類,用來包裝子系統中一個或多個復雜的類,客戶端可以直接通過外觀類來調用內部子系統中方法,從而外觀模式讓客戶和子系統之間避免了緊耦合。

2.2 外觀模式實現

介紹了外觀模式的定義之后,讓我們具體看看外觀模式的由來以及實現,下面與學校中一個選課系統為例來解釋外觀模式,例如在選課系統中,有注冊課程子系統和通知子系統,在不使用外觀模式的情況下,客戶端必須同時保存注冊課程子系統和通知子系統兩個引用,如果后期這兩個子系統發生改變時,此時客戶端的調用代碼也要隨之改變,這樣就沒有很好的可擴展性,下面看看不使用外觀模式下選課系統的實現方式和客戶端調用代碼:

/// <summary>
    /// 不使用外觀模式的情況
    /// 此時客戶端與三個子系統都發送了耦合,使得客戶端程序依賴與子系統
    /// 為了解決這樣的問題,我們可以使用外觀模式來為所有子系統設計一個統一的接口
    /// 客戶端只需要調用外觀類中的方法就可以了,簡化了客戶端的操作
    /// 從而讓客戶和子系統之間避免了緊耦合
    /// </summary>
    class Client
    {
        static void Main(string[] args)
        {
            SubSystemA a = new SubSystemA();
            SubSystemB b = new SubSystemB();
            SubSystemC c = new SubSystemC();
            a.MethodA();
            b.MethodB();
            c.MethodC();
            Console.Read();
        }
    }

    // 子系統A
    public class SubSystemA
    {
        public void MethodA()
        {
            Console.WriteLine("執行子系統A中的方法A");
        }
    }

    // 子系統B
    public class SubSystemB
    {
        public void MethodB()
        {
            Console.WriteLine("執行子系統B中的方法B");
        }
    }

    // 子系統C
    public class SubSystemC
    {
        public void MethodC()
        {
            Console.WriteLine("執行子系統C中的方法C");
        }
    }

然而外觀模式可以解決我們上面所說的問題,下面具體看看使用外觀模式的實現:

 /// <summary>
    /// 以學生選課系統為例子演示外觀模式的使用
    /// 學生選課模塊包括功能有:
    /// 驗證選課的人數是否已滿
    /// 通知用戶課程選擇成功與否
    /// 客戶端代碼
    /// </summary>
    class Student
    {
        private static RegistrationFacade facade = new RegistrationFacade();

        static void Main(string[] args)
        {
            if (facade.RegisterCourse("設計模式", "Learning Hard"))
            {
                Console.WriteLine("選課成功");
            }
            else
            {
                Console.WriteLine("選課失敗");
            }

            Console.Read();
        }
    }

    // 外觀類
    public class RegistrationFacade
    {
        private RegisterCourse registerCourse;
        private NotifyStudent notifyStu;
        public RegistrationFacade()
        {
            registerCourse = new RegisterCourse();
            notifyStu = new NotifyStudent();
        }

        public bool RegisterCourse(string courseName, string studentName)
        {
            if (!registerCourse.CheckAvailable(courseName))
            {
                return false;
            }

            return notifyStu.Notify(studentName);
        }
    }

    #region 子系統
    // 相當於子系統A
    public class RegisterCourse
    {
        public bool CheckAvailable(string courseName)
        {
            Console.WriteLine("正在驗證課程 {0}是否人數已滿", courseName);
            return true;
        }
    }

    // 相當於子系統B
    public class NotifyStudent
    {
        public bool Notify(string studentName)
        {
            Console.WriteLine("正在向{0}發生通知", studentName);
            return true;
        }
    }
    #endregion

使用了外觀模式之后,客戶端只依賴與外觀類,從而將客戶端與子系統的依賴解耦了,如果子系統發生改變,此時客戶端的代碼並不需要去改變。外觀模式的實現核心主要是——由外觀類去保存各個子系統的引用,實現由一個統一的外觀類去包裝多個子系統類,然而客戶端只需要引用這個外觀類,然后由外觀類來調用各個子系統中的方法。然而這樣的實現方式非常類似適配器模式,然而外觀模式與適配器模式不同的是:適配器模式是將一個對象包裝起來以改變其接口,而外觀是將一群對象 ”包裝“起來以簡化其接口。它們的意圖是不一樣的,適配器是將接口轉換為不同接口,而外觀模式是提供一個統一的接口來簡化接口

2.3 外觀模式的結構

看完外觀模式的實現之后,為了幫助理清外觀模式中類之間的關系,下面給出上面實現代碼中類圖:

然而對於外觀模式而言,是沒有一個一般化的類圖描述,下面演示一個外觀模式的示意性對象圖來加深大家對外觀模式的理解:

在上面的對象圖中有兩個角色:

門面(Facade)角色客戶端調用這個角色的方法。該角色知道相關的一個或多個子系統的功能和責任,該角色會將從客戶端發來的請求委派帶相應的子系統中去。

子系統(subsystem)角色可以同時包含一個或多個子系統。每個子系統都不是一個單獨的類,而是一個類的集合。每個子系統都可以被客戶端直接調用或被門面角色調用。對於子系統而言,門面僅僅是另外一個客戶端,子系統並不知道門面的存在。

三、外觀的優缺點

優點:

  1. 外觀模式對客戶屏蔽了子系統組件,從而簡化了接口,減少了客戶處理的對象數目並使子系統的使用更加簡單。
  2. 外觀模式實現了子系統與客戶之間的松耦合關系,而子系統內部的功能組件是緊耦合的。松耦合使得子系統的組件變化不會影響到它的客戶。

缺點:

  1. 如果增加新的子系統可能需要修改外觀類或客戶端的源代碼,這樣就違背了”開——閉原則“(不過這點也是不可避免)。

四、使用場景

 在以下情況下可以考慮使用外觀模式:

  • 外一個復雜的子系統提供一個簡單的接口
  • 提供子系統的獨立性
  • 在層次化結構中,可以使用外觀模式定義系統中每一層的入口。其中三層架構就是這樣的一個例子

五、總結

到這里外觀模式的介紹就結束了,外觀模式,為子系統的一組接口提供一個統一的接口,該模式定義了一個高層接口,這一個高層接口使的子系統更加容易使用。並且外觀模式可以解決層結構分離、降低系統耦合度和為新舊系統交互提供接口功能

本文所有源碼:設計模式之外觀模式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM