外观模式(facade pattern),又称门面模式,是一种结构型模式,能为程序库、框架、复杂系统提供一个高层面的接口,以供客户端或使用者访问。

优点:减少了系统间的相互依赖,提高了系统灵活性,提供了系统安全性。

缺点:不符合开闭原则。

业务场景:系统内部复杂,客户端无需知道系统的复杂,更不能向客户端开放复杂的接口,向客户端开放简单而统一的一个接口即可。

关键代码:在客户端与系统之间增加一个独立的类。该类与客户端解耦。该类与系统耦合,将调用顺序、依赖关系处理好。在这里插入图片描述

家庭影院需求

这个家庭影院有DVD播放器, 投影仪, 屏幕, 环绕立体音响, 还有个爆米花机:
在这里插入图片描述
你可能花了几周的时间去连线, 组装…现在你想看一个电影, 步骤如下:

  1. 打开爆米花机
  2. 开始制作爆米花
  3. 把灯光调暗
  4. 把屏幕放下来
  5. 把投影仪打开
  6. 把投影仪的输入媒介设为DVD
  7. 把投影仪调整为宽屏模式
  8. 打开功放
  9. 把功放的输入媒介设为DVD
  10. 把功放设置为环绕立体声
  11. 把功放的音量调到中档
  12. 把DVD播放器打开
  13. 开始播放DVD

具体用程序描述就是这样的:
在这里插入图片描述
但是还没完,当电影播放完了, 得把所有的设备关掉, 那么反向重新操作一遍?要是听CD或者收音机是不是也同样的麻烦?如果系统升级, 那么你还得学习一遍新的流程吧?

这个需求, 就需要使用外观模式了:

使用外观模式, 你可以通过实现一个外观类把一个复杂的子系统简单化, 因为这个外观类会提供一个更合理的接口.

在这里插入图片描述
HomeTheaterFacade这个外观类只暴露了几个简单的方法, 例如看电影watchMovie(). 这个外观类把整个家庭影院看作是它的子系统, 通过调用子系统的相关方法来实现对外的简单方法.

而客户只需要调用这些简单的方法即可. 但是外观类的子系统仍然保留着对外界的可直接访问性, 如果你需要高级功能, 就可以直接调用.

以下几点需要理解:

  • 外观类并没有"封装"子系统, 它只不过是对子系统的功能额外提供了一套简单的方法. 外界仍然可以直接访问子系统的方法.
  • 外观类也可以添加额外的功能.
  • 针对一个子系统可以创建若干个外观类
  • 外观模式让客户和子系统解耦.
  • 适配器模式是把一个或多个类的接口转化成客户所需要的一个接口, 而外观模式则是提供了一个简单的接口. 它们之间的根本不同是它们的目的,
    适配器是要改变接口, 以便可以符合客户要求; 外观模式则是为子系统提供一个简化的接口.

代码

这里只贴HomeTheaterFacade的代码吧, 其他的东西太简单了 (其他代码在这里: https://github.com/solenovex/Head-First-Design-Patterns-in-CSharp):

using System;
using FacadePattern.Equipments;

namespace FacadePattern.Facades
{
    public class HomeTheaterFacade
    {
        private readonly Amplifier _amp;
        private readonly DvdPlayer _dvd;
        private readonly Projector _projector;
        private readonly TheaterLights _lights;
        private readonly Screen _screen;
        private readonly PopcornPopper _popper;

        public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, Projector projector, TheaterLights lights, Screen screen, PopcornPopper popper)
        {
            _amp = amp;
            _dvd = dvd;
            _projector = projector;
            _lights = lights;
            _screen = screen;
            _popper = popper;
        }

        public void WatchMovie()
        {
            Console.WriteLine("Get ready to watch a movie");

            _popper.On();
            _popper.Pop();
            _lights.Dim(5);
            _screen.Down();
            _projector.On();
            _projector.WideScreenMode();
            _amp.On();
            _amp.SetDvd();
            _amp.SetSurroundSound();
            _amp.SetVolume(5);
            _dvd.On();
            _dvd.Play("Ready Player One");
        }

        public void EndMovie()
        {
            Console.WriteLine("Shutting movie theater down...");
            _popper.Off();
            _lights.On();
            _screen.Up();
            _projector.Off();
            _amp.Off();
            _dvd.Stop();
            _dvd.Eject();
            _dvd.Off();
        }
    }
}

测试

using FacadePattern.Equipments;
using FacadePattern.Facades;

namespace FacadePattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var facade = new HomeTheaterFacade(new Amplifier(), new DvdPlayer(), new Projector(), new TheaterLights(), new Screen(), new PopcornPopper());
            facade.WatchMovie("Ready Player One");
            facade.EndMovie();
        }
    }
}

在这里插入图片描述

来源

使用C# (.NET Core) 实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)
外观模式,了解一二

更多推荐