模式简介
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。
将一个系统拆分成若干个子系统,有利于子系统具有较强地可重用性,也更容易对子系统进行定制。但是与此同时增加了系统的复杂度,外观模式为子系统中较为通用的操作提供了一个简单的接口。如下所示,左图中客户端直接访问子系统,进行一系列复杂地调用,但是对于大多数用户来说,他们并不关心这些调用细节,只希望完成一些基本操作。右图为子系统提供了一个外观类Facade,这个类定义了一个统一的接口,客户端只需要与外观类进行通讯,从而降低了使用成本。
结构说明
角色说明
- Facade
外观类,它知道哪些子系统负责处理请求,将客户端的请求传递给适当的子系统对象。
- Subsystem Classes
子系统类,实现单个的功能,处理由Facade对象指派的任务。
工作原理
客户程序通过发送请求给Facade的方式与子系统通讯,Facade将调用信息传递给适当的子系统对象。使用Facade的客户程序不需要直接访问子系统对象。
示例分析
本节我们讲述一个很古老的问题,把大象放进冰箱,总共需要几步。
第一步:把冰箱门打开
第二步:把大象塞进去
第三步:把冰箱门关上
想想怎样通过程序来实现,这里我们会创建Refrigerator类以及Elephant类,分别代表子系统类。
class Refrigerator
{
public void OpenTheDoor()
{
Console.WriteLine("Open the refrigerator door");
}
public void CloseTheDoor()
{
Console.WriteLine("close the refrigerator door");
}
}
class Elephant
{
public void PutIntoTheRefrigerator()
{
Console.WriteLine("put the elephant into the refrigerator");
}
}
客户端调用:
class Program
{
static void Main(string[] args)
{
Refrigerator refrigerator = new Refrigerator();
refrigerator.OpenTheDoor();
Elephant elephant = new Elephant();
elephant.PutIntoTheRefrigerator();
refrigerator.CloseTheDoor();
Console.ReadLine();
}
}
当然这样没有任何问题。只是我们的客户端并不需要知道这么多的细节,不需要知道Refrigerator类以及Elephant类,只知道我们有一个万能答题工具——AnswerFacade,只需要将问题抛给Facade类,它就能帮助我们回答。
class AnswerFacade
{
private Refrigerator refrigerator = new Refrigerator();
private Elephant elephant = new Elephant();
public void Answer()
{
refrigerator.OpenTheDoor();
elephant.PutIntoTheRefrigerator();
refrigerator.CloseTheDoor();
}
}
客户端调用:
class Program
{
static void Main(string[] args)
{
AnswerFacade facade = new AnswerFacade();
facade.Answer();
Console.ReadLine();
}
}
输出结果:
适用场景
要为一个复杂的系统提供一个简单的接口。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
在层次话结构当中,可以适用外观模式定义系统中每一曾的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合。
使用外观模式的优点
对客户端隐藏了子系统组件,减少了客户端处理的对象的数量,使得子系统使用起来更加方便。
- 实现了客户端与子系统之间的松耦合,子系统的组件修改不会直接影响到客户端,只需要调整外观类即可。
只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类,可根据需要直接对子系统类进行调用。