Facade(外观)设计模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。

Facade设计模式概述:

       实际应用中,我们在对付一些老旧的code,或者即使不是老旧的code,但涉及多个子系统时,除了重写全部代码,我们还可以采用这样一种策略:重新进行类的设计,将原来分散的代码的类、结构以及方法重新组合,形成新的,统一的接口供上层应用使用。

       看上去貌似与Adapter模式和proxy有相似之处,但是,proxy(代理)注重在为客户端提供一个访问的中间层,如corba可以为应用程序提供透明访问支持,使应用程序无需去考虑平台及网络造成的差异,以及其他诸多技术细节;而Adapter设计模式注重的是对接口的转换以及调整;而facade设计模式所面对的往往是多个类或其他程序单元,通过重新组合各类及程序单元,对外提供统一的界面或接口。

Facade设计模式应用:

       在遇到以下情况时,可以考虑使用Facade设计模式:

       1. 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化变得越来越复杂,大多数模式使用时都会产生更多跟小的类,这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来使用上的困难。facade可以提供一个简单的缺省的视图,这一视图对大多数用户来说已经足够了,而那些需要更多的可定制性的用户可以越过facade层。

       2. 客户端程序与抽象类的实现部分之间存在着很大的依赖,引入facade将这个子系统与客户端程序以及其他子系统进行分离,可以提高子系统的独立性和可移植性。

       3. 当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点,如果子系统之间时相互依赖的,你可以让他们仅通过facade进行通讯,从而简化了他们之间的依赖关系。

Facade设计模式的优缺点:

     1. 它对客户端屏蔽了子系统组件,因而减少了客户端处理的对象的数目并使得子系统使用起来更加方便。

       2. 它实现了子系统与客户端之间的松散耦合关系,而子系统内部的功能组件往往时紧密耦合的。

       3. 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为一般编译一个子系统不需要编译其他子系统,一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。

Facade模式的缺点:

       1. 不能很好的限制客户使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。

       2. 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或者客户端的源代码,违背了“开闭原则”

Facade设计模式实例:

     我们来看一个网上广为流传的例子:

       有一个抽屉,里面放了很重要的文件,我们称这个抽屉为第二个抽屉,它的钥匙放在另外一个抽屉里面,我们称之为第一个抽屉,只有拿到第一个抽屉的钥匙,才能打开第二个抽屉。

package com.howlaa.facadeMode;  
  
/** 
 *  抽屉一 
 * @author howlaa 
 */  
public class DrawerOne {  
    public String open(){  
        System.out.println("第一个抽屉打开...");  
        return getKey();  
    }  
    public String getKey(){  
        System.out.println("得到第二个抽屉的钥匙...");  
        return "钥匙";  
    }  
}


package com.howlaa.facadeMode;  
  
/** 
 * 抽屉二  
 * @author howlaa 
 */  
public class DrawerTwo {  
    public void open(String key){  
        if("钥匙".equals(key)){  
            System.out.println("第二个抽屉打开...");  
            getFile();  
        }else  
        {  
            System.out.println("钥匙不匹配,不法打开第二个抽屉...");  
            return ;  
        }  
          
    }  
    public void getFile(){  
        System.out.println("取得重要文件...");  
    }  
}




      

现在我们来看下,如果我们不使用facade设计模式,客户端用户如果想拿到这个文件时怎样的:


package com.howlaa.facadeMode;  
  
import org.junit.Test;  
  
/** 
 * 客户端 
 * @author howlaa 
 * 
 */  
public class Client {  
    /*-------当未使用Facade模式时---------*/  
    @Test  
    public void NotUseFacade(){  
        DrawerOne drawerOne = new DrawerOne();  
        String key = drawerOne.open();  
        DrawerTwo drawerTwo = new DrawerTwo();  
        drawerTwo.open(key);  
    }  
    /*-------end 未使用Facade模式---------*/  
}



      可以看到,用户必须先去打开第一个抽屉,才能用这个钥匙去打开第二个抽屉。在实际中,可能用户不知道或是完全不必知道这个条件,它知道的时它需要打开抽屉,拿到这个重要文件。我们来看下如果我们使用了facade模式,客户端程序会怎样:

首先,新建一个facade类:


package com.howlaa.facadeMode;  
  
public class DrawerFacade {  
    DrawerOne drawerOne = new DrawerOne();  
    DrawerTwo drawerTwo = new DrawerTwo();  
    public void open(){  
        String key = drawerOne.open();  
        drawerTwo.open(key);  
    }  
}



客户端直接操作这个facade类即可:


package com.howlaa.facadeMode;  
  
import org.junit.Test;  
  
/** 
 * 客户端 
 * @author howlaa 
 * 
 */  
public class Client {     
    /*--------使用Facade模式--------------*/  
    @Test  
    public void UseFacade(){  
        DrawerFacade drawerFacade = new DrawerFacade();  
        drawerFacade.open();  
    }  
    /*--------end 使用Facade模式----------*/  
}