一、动机(Motivate)
在软件系统开发的过程中,当组件的客户(即外部接口,或客户程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?
二、意图(Intent)
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 ——《设计模式》GoF
三、结构图(Structure)
四、模式的组成
外观模式包含如下两个角色:
(1)、外观角色(Facade):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。
(2)、子系统角色(SubSystem):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
五、外观模式的具体实现
购物的过程很复杂,但是我们在购买的过程只需要选择自己喜欢的商品,也可以加入购物车,最后点击付款就完成了。其实这个过程没有那么简单。我们下面就模仿一下购买的过程吧。
购买过程有几点必须要做的事情:
1、身份验证安全,没有认证是无效用户。
2、系统安全,检查系统环境,防止注入、跨站和伪造等攻击
3、网银安全,检查付款地址的有效性,检查网关是否正常
/// <summary> /// 不使用外观模式的情况 /// 此时客户端与三个子系统都发送了耦合,使得客户端程序依赖与子系统 /// 为了解决这样的问题,我们可以使用外观模式来为所有子系统设计一个统一的接口 /// 客户端只需要调用外观类中的方法就可以了,简化了客户端的操作 /// 从而让客户和子系统之间避免了紧耦合 /// </summary> static void Main(string[] args) { SystemFacade facade = new SystemFacade(); facade.Buy();//用户点击购买就完成了。 } // 身份认证子系统A public class AuthoriationSystemA { public void MethodA() { Console.WriteLine("执行身份认证"); } } // 系统安全子系统B public class SecuritySystemB { public void MethodB() { Console.WriteLine("执行系统安全检查"); } } // 网银安全子系统C public class NetBankSystemC { public void MethodC() { Console.WriteLine("执行网银安全检测"); } } //更高层的Facade public class SystemFacade { private AuthoriationSystemA auth; private SecuritySystemB security; private NetBankSystemC netbank; public SystemFacade() { auth = new AuthoriationSystemA(); security = new SecuritySystemB(); netbank = new NetBankSystemC(); } public void Buy() { auth.MethodA();//身份认证子系统 security.MethodB();//系统安全子系统 netbank.MethodC();//网银安全子系统 Console.WriteLine("我已经成功购买了!"); } }
六、实现要点:
1、一个系统可以有几个门面类
在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。当然这并不意味着在整个系统里只有一个门面类,而仅仅是说对每一个子系统只有一个门面类。或者说,如果一个系统有好几个子系统的话,每一个子系统都有一个门面类,整个系统可以有数个门面类。
2、为子系统增加新行为
初学者往往以为通过继承一个门面类便可在子系统中加入新的行为,这是错误的。门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。比如医院中的接待员并不是医护人员,接待员并不能为病人提供医疗服务。
3、Facade有助于建立层次结构的系统,实现了子系统与客户之间的松耦合关系,子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。Facade消除了复杂的循环依赖关系。这一点在客户程序与子系统分别实现的时候格外重要。
4、从客户程序的角度来看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。
1、外观模式的优点:
(1)、外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单。
(2)、外观模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件是紧耦合的。松耦合使得子系统的组件变化不会影响到它的客户。
2、外观模式的缺点:
(1)、如果增加新的子系统可能需要修改外观类或客户端的源代码,这样就违背了”开——闭原则“(不过这点也是不可避免)。
3、在以下情况下可以考虑使用外观模式:
(1)、外一个复杂的子系统提供一个简单的接口
(2)、提供子系统的独立性
(3)、在层次化结构中,可以使用外观模式定义系统中每一层的入口。其中三层架构就是这样的一个例子。
七.NET 中外观模式的实现
外观模式在FCL里面运用还是很多的,多数情况是单个类的情况,在Asp.Net里面,有很多复合控件,比如:Login控件,可以登录,可以认证,可以保存登录用户信息。其实,外观模式更多的是应用在业务系统当中,效果更好。