医院的例子:
现代的软件系统都是比较复杂的,设计师处理复杂系统的一个常见方法便是将其“分而治之”,把一个系统划分为几个较小的子系统。如果把医院作为一个子 系统,按照部门职能,这个系统可以划分为挂号、门诊、划价、化验、收费、取药等。看病的病人要与这些部门打交道,就如同一个子系统的客户端与一个子系统的 各个类打交道一样,不是一件容易的事情。
首先病人必须先挂号,然后门诊。如果医生要求化验,病人必须首先划价,然后缴费,才可以到化验部门做化验。化验后再回到门诊室。
上图描述的是病人在医院里的体验,图中的方框代表医院。
解决这种不便的方法便是引进外观模式,医院可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。这个接待员就是门面模式的体现,病人只接触接待员,由接待员与各个部门打交道。
外观模式的结构:
再具体复杂一点
参与者:
Facade: 外观角色。知道哪些子系统类负责处理请求,将客户的请求代理给适合的子系统处理。
SubSystem:子系统角色。实现子系统功能,处理Facade对象发来的请求。
代码实现:
moduleA:
1 public class ModuleA { 2 //示意方法 3 public void testA(){ 4 System.out.println("调用ModuleA中的testA方法"); 5 } 6 }
moduleB:
1 public class ModuleB { 2 //示意方法 3 public void testB(){ 4 System.out.println("调用ModuleB中的testB方法"); 5 } 6 }
moduleC:
1 public class ModuleC { 2 //示意方法 3 public void testC(){ 4 System.out.println("调用ModuleC中的testC方法"); 5 } 6 }
外观角色Facade类:
1 public class Facade { 2 //示意方法,满足客户端需要的功能 3 public void test(){ 4 ModuleA a = new ModuleA(); 5 a.testA(); 6 ModuleB b = new ModuleB(); 7 b.testB(); 8 ModuleC c = new ModuleC(); 9 c.testC(); 10 } 11 }
客户端:
1 public class Client { 2 3 public static void main(String[] args) { 4 5 Facade facade = new Facade(); 6 facade.test(); 7 } 8 9 }
Facade类实际上相当于子系统对外部的接口,客户端不需要亲自调用子系统的内部的类,也不需要关心怎么实现的,甚至不需要关系系统内部有几个模块。客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。
外观模式的另外的好处是能够有选择性地暴露方法。一个模块中定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部模块之间相互调用时使用的。有了Facade类,那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了。
例如:
1 public class Module { 2 /** 3 * 提供给子系统外部使用的方法 4 */ 5 public void a1(){}; 6 7 /** 8 * 子系统内部模块之间相互调用时使用的方法 9 */ 10 private void a2(){}; 11 private void a3(){}; 12 }
1 public class ModuleB { 2 /** 3 * 提供给子系统外部使用的方法 4 */ 5 public void b1(){}; 6 7 /** 8 * 子系统内部模块之间相互调用时使用的方法 9 */ 10 private void b2(){}; 11 private void b3(){}; 12 }
1 public class ModuleC { 2 /** 3 * 提供给子系统外部使用的方法 4 */ 5 public void c1(){}; 6 7 /** 8 * 子系统内部模块之间相互调用时使用的方法 9 */ 10 private void c2(){}; 11 private void c3(){}; 12 }
1 public class ModuleFacade { 2 3 ModuleA a = new ModuleA(); 4 ModuleB b = new ModuleB(); 5 ModuleC c = new ModuleC(); 6 /** 7 * 下面这些是A、B、C模块对子系统外部提供的方法 8 */ 9 public void a1(){ 10 a.a1(); 11 } 12 public void b1(){ 13 b.b1(); 14 } 15 public void c1(){ 16 c.c1(); 17 } 18 }
这样facade类就可以屏蔽module类中的实现细节,封装一些内部调用的方法,客户端也不会知道这些方法的存在。
外观模式的优点:
● 松散耦合
门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
● 简单易用
门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。
● 更好的划分访问层次
通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。
类 与类之间的耦合越低,那么可复用性就越好,如果两个类不必彼此通信,那么就不要让这两个类发生直接的相互关系,如果需要调用里面的方法,可以通过第三者来 转发调用。外观模式非常好的诠释了这段话。外观模式提供了一个统一的接口,用来访问子系统中的一群接口。它让一个应用程序中子系统间的相互依赖关系减少到 了最少,它给子系统提供了一个简单、单一的屏障,客户通过这个屏障来与子系统进行通信。
通过使用外观模式,使得客户对子系统的引用变得简单了,实现了客户与子系统之间的松耦合。但是它违背了“开闭原则”,因为增加新的子系统可能需要修改外观类或客户端的源代码。
参考文章
http://blog.csdn.net/jason0539/article/details/22775311