Java外观模式

不好意思上一篇外观模式没有完稿,在此重新写一下。

外观模式
产生原因
       在软件开发过程中,程序一般会越做越大,而这样系统中类及子系统之间的影响会使彼此间的关系变得错综复杂即过多的耦合,这就导致了随着系统中类或子系统发生变化,与之相关联的子系统或类就需要发生变化
         ”如何应对变化“是软件系统开发过程中非常重要的一个问题。生活在一个动态的世界,我们不能杜绝变化的发生,但我们可以通过一些手段让变化降至最低。
          本节课所学习的Façade模式正式解决这种问题的方法之一。下面我们先通过两个例子理解一下:

举例
1.电源总开关
为了使用方便,一个电源总开关可以控制两盏灯、一台空调和一台电视机的启动和关闭。通过该电源总开关可以同时控制上述所有电器设备,使用外观模式设计该系统。

 


2.旅游照相
      几乎每个人都喜欢旅游,那旅游要带个相机吧。现在单反数码相机很多见,但是不是人人都会用。沿途不仅要记录下美好的风光,更重要的还要给自己拍几张留念。可是有时候找了半天没找到一个会用的路人,别着急,把相机跳到自动档,按下快门就可以了。这也跟外观模式很像。

外观模式
模式定义
外观模式又称为门面模式,它是一种对象结构型模式。
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
更简单的理解外观模式
       通过外观的包装,使客户程序只能看到外观对象而不会看到具体细节对象。从而降低了系统的复杂度,并提高了程序的可维护性。
       如同黑匣子

下面来看一下未使用Facade模式的结构

 

随着子系统和客户程序的增加,造成了高度耦合,看图

于是我们自然而然的会想到运用程序设计里边所学,把Client和Subsystem封装起来,提供一个统一的接口。

外观模式动机
引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,将复杂系统的内部子系统与客户程序之间的依赖解耦,降低了系统的耦合度。

它侧重于简化接口,更多的是一种架构模式。
Frequency of use: high
模式结构
外观模式包含如下两个角色:
 Facade: 外观角色
          外观角色是在客户端直接调用的角色

          SubSystem:子系统角色
          在软件系统中可以同时有一个或者多个子系统角色


 

 

w模式分析
      根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性。引入一个外观对象,它为子系统的访问提供了一个简单而单一的入口。
      外观模式也是“迪米特法则”的体现,通过引入一个新的外观类可以降低原有系统的复杂度,同时降低客户类与子系统类的耦合度。
      外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观对象打交道,而不需要与子系统内部的很多对象打交道。

外观模式的目的在于降低系统的复杂程度

外观模式从很大程度上提高了客户端使用的便捷,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能。
下面让我们看一下典型的外观角色代码 :
 
public class Facade
{
    private SubSystemA obj1 = new SubSystemA();
    private SubSystemB obj2 = new SubSystemB();
    ……………
public void method()
    {
        obj1.method();
        obj2.method();
        …………………}
}
  
w外观模式实例与解析
以计算机的加载和关闭过程为例
 
子系统角色:CPU、内存和硬盘。
    外观角色:计算机。
    客户:用户。
它们之间的依赖关系如图所示:

 

下面来看具体的实现。
(1)CPU类CPU.java  其中定义了启动和关闭CPU的函数。
CPU类CPU.java
package structure.facade;  
 
public class CPU {  
    public void startup() {  }       
    public void shutdown() {   }  
(2)内存类Memory.java其中定义了加载和清空内存的函数。
    内存类Memory.java
package structure.facade;  
 
public class Memory {  
    public void startup() {  }   
    public void shutdown() { }  
(3)硬盘类Disk.java其中定义了加载和卸载硬盘的函数。
  硬盘类Disk.java
package structure.facade;  
 
public class Disk {  
    public void startup() {    }       
    public void shutdown() {  }  
(4)外观模式类Computer.java 其中包含了CPU、内存和硬盘3个类对象,并定义了启动和关闭计算机的函数,在启动和关闭时批量地启动和关闭CPU、内存和硬盘。
外观模式类Computer.java
package structure.facade;  
 /*  外观模式   */ 
public class Computer {  
      private CPU  cpu = new CPU(); ……. 
       //声明对象      
    public void startup() { // 调用对象的方法   }      
    public void shutdown() {// 调用对象的方法 }  
(5)用户类User.java,我们只需要调用Computer.java的函数来启动和关闭计算机,而不需要依次加载和关闭CPU、内存和硬盘。
用户类User.java
package structure.facade;  
 
public class User {  
    public static void main(String args[]) {  
        Computer computer = new Computer();  
        computer.startup();  //调用
        computer.shutdown();  
    }  
总结:
从程序可以看出,通过Computer一个外观类即可实现计算机所有部件的控制,而不需要单独去控制其所有的部件,这正是外观模式的作用。
模式优缺点
外观模式的优点
•对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。同时,客户代码变简单
• 实现了子系统与客户之间的松耦合关系。       
   降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程。
•只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
 
外观模式的缺点
•不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
•在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
w模式适用环境
在以下情况下可以使用外观模式:
•当要为一个复杂子系统提供一个简单接口时可以使用外观模式。
•客户程序与多个子系统之间存在很大的依赖性。
•在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
模式扩展
一个系统有多个外观类
•在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。
w模式扩展注意
不要试图通过外观类为子系统增加新行为
•不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。
•外观模式的用意:为子系统提供一个集中化和简化的沟通渠道
外观模式与迪米特法则
•外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。
外观模式就是实现代码重构以便达到迪米特法则要求的一个强有力的武器。
 
抽象外观类的引入
•外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。
 
posted @ 2012-05-07 18:18  dobetter  阅读(1208)  评论(1编辑  收藏  举报