2.7設計模式之外觀模式(Facade)

2.7.1 模式意圖:

系統中常含有多個子系統,隨著子系統不斷增多,如果始終保持對子系統的直接調用,會明顯提高業務邏輯和子系統間的耦合度,造成系統混亂,加大閱讀困難,這時我們可以使用外觀模式,用此模式持有多個子系統的引用,通過外觀這個中間層達到由原來的多對多轉變為一對多的情況,對多個子系統的調用就像使用菜單一樣,一目了然,利于代碼的閱讀理解和維護。

2.7.2 模式概念:

又稱為門面模式,屬于結構型模式。為子系統中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。

2.7.3 模式元素:

  • 外觀(Facade)
  • 子系統(IPhysicalSystem、IRenderingSystem、IMoveSystem)

2.7.4 代碼示例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Custom.Log;

interface IPhysicalSystem
{
    void Initialize();
    void Update();
}
interface IRenderingSystem
{
    void Initialize();
    void Update();
}
interface IMoveSystem
{
    void Initialize();
    void Update();
}

public class PhysicalSystem : IPhysicalSystem
{
    public void Initialize() { Degbug.Log($"初始化{nameof(PhysicalSystem)}"); }
    public void Update() { Degbug.Log($"更新{nameof(PhysicalSystem)}"); }
}
public class RenderingSystem : IRenderingSystem
{
    public void Initialize() { Degbug.Log($"初始化{nameof(RenderingSystem)}"); }
    public void Update() { Degbug.Log($"更新{nameof(RenderingSystem)}"); }
}
public class MoveSystem : IMoveSystem
{
    public void Initialize() { Degbug.Log($"初始化{nameof(MoveSystem)}"); }
    public void Update() { Degbug.Log($"更新{nameof(MoveSystem)}"); }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Custom.Log;
public class Facade
{
    #region Facade
    static Facade() { }
    private Facade() { }

    private readonly static object staticsync = new object();

    private volatile static Facade instance = null;

    public static Facade Instance
    {
        get
        {
            if (instance == null)
            {
                lock (staticsync)
                {
                    if (instance == null)
                    {
                        instance = new Facade();
                    }
                }
            }
            return instance;
        }
    }
    #endregion

    private IMoveSystem moveSystem = new MoveSystem();
    private IPhysicalSystem physicalSystem = new PhysicalSystem();
    private IRenderingSystem renderingSystem = new RenderingSystem();
    public void Initialize()
    {
        moveSystem.Initialize();
        physicalSystem.Initialize();
        renderingSystem.Initialize();
    }

    public void Update()
    {
        moveSystem.Update();
        physicalSystem.Update();
        renderingSystem.Update();
    }
}

調用

public class FacadeComponent : MonoBehaviour
{
    Facade facade = null;

    void Start()
    {
        facade = Facade.Instance;
        facade.Initialize();
    }

    private void Update()
    {
        facade.Update();
    }
}

2.7.5 寫法對比:

2.7.6 模式分析:

外觀模式相對于其他設計模式來講是一種既簡單又實用的編程技巧。
其實外觀模式的這種思想在生活中也有很廣的應用,例如: 1.我們去餐廳吃飯時菜單和點菜器,這就是一種外觀模式的體現,我們不需要跟各類廚師進行交互,只需要對菜單發出“指令”即可。 2.電腦的開機鍵,一鍵開機,不需要通知CPU、顯卡、內存、硬盤等電子元件開始工作。

這種結構,使得我們上層調用的時候不需要知道明確的子系統,只需要知道Facade定義的對應函數即可,降低耦合度,符合迪米特法則,但它的缺點就是破壞了開閉原則,如果后期子系統有改動,Facade會變動比較頻繁。

還有一個要注意的是,Facade只能調用其子系統中含有的函數,完成對各個子系統自帶函數的拼裝不能自建新的業務邏輯,例如我們的示例,要在Facade類里面根據moveSystem添加新的業務邏輯這個是不允許的,,而且外觀模式封裝的是單向交互,是從客戶端訪問系統的調用,不允許從系統中來訪問客戶端的調用。

這些注意要素其實在PureMVCFramework中就有很好的體現,在對應的Facade類中(如下所示),僅僅就是模型、視圖、控制層這些子系統的單向調用自身函數,并沒有添加一些其他的自建業務邏輯。

namespace PureMVC.Patterns.Facade
{
    public class Facade : IFacade
    {
        //省略其他代碼***
        public virtual void RegisterCommand(string notificationName, Func<ICommand> commandFunc)
        {
            controller.RegisterCommand(notificationName, commandFunc);
        }

        public virtual void RemoveCommand(string notificationName)
        {
            controller.RemoveCommand(notificationName);
        }

        public virtual bool HasCommand(string notificationName)
        {
            return controller.HasCommand(notificationName);
        }

        public virtual void RegisterProxy(IProxy proxy)
        {
            model.RegisterProxy(proxy);
        }

        public virtual IProxy RetrieveProxy(string proxyName)
        {
            return model.RetrieveProxy(proxyName);
        }

        public virtual IProxy RemoveProxy(string proxyName)
        {
            return model.RemoveProxy(proxyName);
        }

        public virtual bool HasProxy(string proxyName)
        {
            return model.HasProxy(proxyName);
        }
    }
}

2.7.7 應用場景:

需要對多個子系統的單向調用。

2.7.8 小結:

利用外觀模式來降低業務邏輯與各子系統間的耦合度,同時也要注意后續頻繁改動需求,引起的Facade類發生一系列改變而帶來的風險。


更多設計模式詳見:設計模式全家桶

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容