问题:
在软件系统开发中经常会遇到这样的情况,在一个系统中实现了一些接口(模块),而这些接口(模块)都分布在几个类或几个子系统模块中比如A和B、C、D,各自实现了一些功能接口。然后对于客户,并不知道或并不想知道,这些功能接口是怎么样实现的,是在哪里实现的。外观模式可以为一个复杂的系统(有很多分布在不同类或子系统中的方法)提供一个简单的供客户端调用的接口,使耦合大大降低
定义:
外观模式(Facade,也叫门面模式)是一种构造型设计模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
意图:
提供一个接口,这个接口能够把其他可重用类(代码,子系统)的行为有效的组织起来,对一个子系统的类进行重构,它将客户的请求代理给适合的子系统对象的方式与子系统通信。使用(Facade)的客户不需要直接访问子系统对象。 减少了客户处理的对象的数目,使耦合大大降低。比如:经典的三层架构,业务层提供一个保存方法,保存时需要调用A的修改、B的删除、C的添加,保存方法里需要调用这么多对象的方法才能完成所有工作,但对于外面控制层,看到的业务层就一个保存方法,调用这个保存方法,就能完成A、B、C的全部工作。
客户端不需要关心子系统,它只需要关心Facade所留下来的和外部交互的接口,而子系统是在中聚合。
参与者:
•外观角色( Facade):
外观角色是在客户端直接调用的角色
•子系统角色(SubSystem):
在软件系统中可以同时有一个或者多个子系统角色。
UML:
实例说明:
诺基亚手机工厂
对于公司来说不关心生产部的生产细节,只通知生产部生产手机即可,不关心 硬件组,软件组以及测试组 是怎么工作的。
uml图如下:
代码:
/// 手机生产外观类
/// </summary>
public class FacadePhone
{
SetHardware setHardware = null;
SetSoftware setSoftware = null;
Test test = null;
public FacadePhone()
{
setHardware = new SetHardware();
setSoftware = new SetSoftware();
test = new Test();
}
/// <summary>
/// 生产N8
/// </summary>
public void CreateN8()
{
//安装主板
setHardware.SetMb();
//安装CPU
setHardware.SetCpu();
//安装系统软件
setSoftware.SetSystem();
//安装应用软件
setSoftware.SetApp();
//测试
test.TestPhone();
}
/// <summary>
/// 生产N9
/// </summary>
public void CreateN9()
{
//安装主板
setHardware.SetMb();
//安装CPU
setHardware.SetCpu();
//安装系统软件
setSoftware.SetSystem();
//安装应用软件
setSoftware.SetApp();
//测试
test.TestPhone();
}
}
/// <summary>
/// 子系统模块 安装硬件
/// </summary>
public class SetHardware
{
public void SetMb()
{
System.Console.WriteLine("安装主板");
}
public void SetCpu()
{
System.Console.WriteLine("安装CPU");
}
}
/// <summary>
/// 子系统模块 安装软件
/// </summary>
public class SetSoftware
{
public void SetSystem()
{
System.Console.WriteLine("安装系统软件");
}
public void SetApp()
{
System.Console.WriteLine("安装应用软件");
}
}
/// <summary>
/// 子系统模块 测试
/// </summary>
public class Test
{
public void TestPhone()
{
System.Console.WriteLine("测试手机");
}
}
/// <summary>
/// 客户端测试
/// </summary>
void FacadeTest()
{
FacadePhone fp = new FacadePhone();
fp.CreateN8();
}
优点:
•它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
•它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
缺点:
•增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
•对客户访问子系统类做太多的限制则减少了可变性和灵活性。
应用情景:
•当要为一个复杂子系统提供一个简单接口时可以使用外观模式。
•客户程序与多个子系统之间存在很大的依赖性。
•在分层结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
PS:
•从客户程序的角度看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果,松耦合关系使得子系统的组件变化不会影响到它的客户。
•Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层,注重从架构的层次去看整个系统,而不是单个类的层次Facade很多时候更是一种架构设计模式。
•不要试图通过外观类为子系统增加新行为,外观模式的用意是为子系统提供一个集中化和简单的接口。
•某种意义上与Adapter及Proxy有类似之处,但是,Proxy(代理)注重在为Client-Subject提供一个访问的中间层,如CORBA可为应用程序提供透明访问支持,使应用程序无需去考虑平台及网络造成的差异及其它诸多技术细节;Adapter(适配器)注重对接口的转换与调整;而Facade所面对的往往是多个类或其它程序单元,通过重新组合各类及程序单元,对外提供统一的接口/界面。