设计模式--外观模式
程序员文章站
2022-06-28 17:22:45
1. 外观模式的引入如医院的就诊的情况(医院—子系统,外观—导医)客户端程序与完成实际业务功能的子系统程序之间通信时采用的2种方案:上述A方案的问题在于组件的客户(即外部接口,或客户端程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得...
1. 外观模式的引入
如医院的就诊的情况(医院—子系统,外观—导医)
客户端程序与完成实际业务功能的子系统程序之间通信时采用的2种方案:
- 上述A方案的问题在于组件的客户(即外部接口,或客户端程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。
- 如何简化外部客户程序和系统间的交互接口?
- 如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?
子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
——《设计模式》GoF
2. 外观模式的结构
外观模式是对象的结构模式。外观模式没有一个一般化的类图描述,下图演示了一个外观模式的示意性对象图:
这种结构不仅体现了类的单一职责原则,而且也体现了开放/封闭原则。子系统和系统之间是组合关系,而不是继承关系。高层总是相对稳定,低层总是相对易变。所以我们应该尽量依赖高层抽象,而不是低层细节实现。
- 外观(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
- 子系统(SubSystem)角色:可以同时有一个或者多个子系统。**每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色调用。**子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。
- 需要注意的2点:
- 外观类通常是单例类;
- 扩展功能不应该继承外观类,而是在子系统代码中扩展,外观类只是为对子系统的访问提供一个集中化的、简化的渠道。
3. 示例
保安系统:由两个录像机、三个电灯、一个遥感器和一个警报器组成,保安系统的操作人员需要经常将这些仪器启动和关闭。
示例:SecurityClassical(未用外观模式的代码,耦合非常大)
using System;
using System.Collections.Generic;
using System.Text;
namespace SecurityClassical
{
class Program
{
static void Main(string[] args)
{
//客户端程序需要面临众多的子系统内部的类,以及众多的子系统内部的对象
Camera camera1, camera2;
Light light1, light2, light3;
Sensor sensor;
Alarm alarm;
//客户端程序直接创建子系统内部的类的对象
camera1 = new Camera();
camera2 = new Camera();
light1 = new Light();
light2 = new Light();
light3 = new Light();
sensor = new Sensor();
alarm = new Alarm();
//客户端程序直接调用子系统内部的类的方法--启动
camera1.TurnOn();
camera2.TurnOn();
light1.TurnOn();
light2.TurnOn();
light3.TurnOn();
sensor.Activate();
alarm.Activate();
alarm.Ring();
Console.WriteLine();
Console.WriteLine("Other Operations...");
Console.WriteLine();
//客户端程序直接调用子系统内部的类的方法--关闭
camera1.TurnOff();
camera2.TurnOff();
light1.TurnOff();
light2.TurnOff();
light3.TurnOff();
sensor.Deactivate();
alarm.StopRing();
alarm.Deactivate();
Console.Read();
//以上代码使客户端程序与子系统耦合极大
}
}
}
示例: SecurityFacade(使用外观模式)
using System;
using System.Collections.Generic;
using System.Text;
namespace SecurityFacade
{
/// <summary>
/// 外观类
/// </summary>
public class Facade
{
//内部封装了子系统的对象
private Camera camera1, camera2;
private Light light1, light2, light3;
private Sensor sensor;
private Alarm alarm;
public Facade()
{
//子系统的对象由外观类创建
camera1 = new Camera();
camera2 = new Camera();
light1 = new Light();
light2 = new Light();
light3 = new Light();
sensor = new Sensor();
alarm = new Alarm();
}
//对子系统中对象操作的封装--启动
public void Activate()
{
camera1.TurnOn();
camera2.TurnOn();
light1.TurnOn();
light2.TurnOn();
light3.TurnOn();
sensor.Activate();
alarm.Activate();
alarm.Ring();
}
//对子系统中对象操作的封装--关闭
public void Deactivate()
{
camera1.TurnOff();
camera2.TurnOff();
light1.TurnOff();
light2.TurnOff();
light3.TurnOff();
sensor.Deactivate();
alarm.Deactivate();
alarm.StopRing();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace SecurityFacade
{
class Program
{
static void Main(string[] args)
{
Facade security = new Facade();
//通过外观对象访问子系统,避免与子系统过多耦合
security.Activate();
Console.WriteLine();
Console.WriteLine("Other Operations...");
Console.WriteLine();
security.Deactivate();
Console.Read();
}
}
}
4. 外观模式的应用
- 设计初期阶段
有意识的建立三层架构,层与层之间建立外观Facade(层间接口)。 - 开发阶段
子系统往往因为不断的重构演化而变得越来越复杂,大规模的使用模式会产生很多很小的类,这将使维护工作变得复杂,而Facade会减少它们之间的依赖—子系统通过Facade对象向外提供服务。 - 维护阶段
维护一个遗留的大系统时,Facade可以负责与遗留代码的复杂的交互工作(类似适配器)。
5.外观模式的总结
- 从客户程序的角度来看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。
- Facade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。
- 注意区分Facade模式、Adapter模式、Bridge模式与Decorator模式:
Facade模式注重简化接口
Adapter模式注重转换接口
Bridge模式注重分离接口(抽象与其实现)
Decorator模式注重稳定接口的前提下为对象扩展功能
本文地址:https://blog.csdn.net/qq_41342326/article/details/107500235