定义
外观模式是使用频率非常高的一种设计模式,用于隔离客户端与复杂子系统的关联关系,参考迪米特法则可知,该模式的结构是在客户端与子系统之间引入一个“外观”类,满足客户端需求针对“外观”对象提出即可,具体的实现交给“外观”对象来完成。
最基本实现如下
由上图可知,将原本耦合度较高的客户端与复杂系统分隔开,客户端只需要向facade对象,即外观对象,提出需求即可(从这里看有点像之前提到的适配器模式,客户端发出目标请求,利用适配器来转接到其他现有的功能上来完成,适配器发挥的是个转移执行作用,外观类则只是简化调用关系)。从单一职责方面出发,整个结构可以分为两个部分:功能定义、执行,复杂系统表现的是定义功能部分,客户端则属于功能执行部分,只不过此处的执行关系比较复杂,也就是耦合度较高,不利于扩展,所以参考迪米特法则,引入外观类来解耦合。
结构
由外观模式定义可知,结构有如下部分
客户端:发出目标需求的一方,即执行系统提供功能的发起方,与外观类具有关联关系
外观类:与复杂系统进行直接关联,调用系统功能来完成客户端需求
系统部分:具体功能的提供方,定义执行内容
结构中各个部分的关系比较清晰,客户端针对外观对象发出请求,而不用知道具体的子系统是如何实现的,外观类解耦了请求的发起方和功能的实现方,其实就相当与将客户端与子系统之间的复杂耦合关系过渡到自身上来实现。因此外观对象必须清楚子系统的具体功能,即外观类的职责就是处理与各个具体子系统的功能调用,来完成客户端的需求,进行这层转换的目的当然是看重了外观类的可重用性(最简单例子就是,食堂窗口排队打饭,每个人只需要说自己需要a菜,b菜,c菜即可,服务员打好饭把餐盘交给你。排队的人不需要知道每个菜在哪摆放,直接发出目标需求,这里就是客户端角色,服务员则必须清楚知道每个菜的摆放位置以及怎么装菜操作,这里服务员就是外观对象)。
结构如下
由上结构图可知,客户端的需求只需要告知facade对象,具体调用关系交给facade外观类来实现,即外观类只负责简化客户端操作,并不添加任何新的系统功能。从当前结构很明显可以看出一个问题是,client对于facade是面向具体对象操作,在当前操作外观类中添加一个新的需求,则需要更改facade类的实现,即不符合开闭原则,毕竟有些情况下使用的是已经编译后的文件,并没有提供对源码的修改支持,解决方式很简单,建立抽象外观类即可。
如图
参考代码
public class t{
public static void main(String[] args){
List<String> list=new ArrayList<String>();//添加要吃什么菜
list.add("宫保鸡丁");
list.add("椒盐蘑菇");
list.add("冬瓜排骨");
AbstractFacade server=facade.getInstance();//以单例方式进行
server.meal(list);//向外观对象发出请求
}
}
abstract class AbstractFacade{//抽象外观类
abstract public void meal(List<String> list);
}
class facade extends AbstractFacade{//具体外观类
private static facade server=new facade();//简单起见,使用懒汉单例方式
private static HashSet<dish> arr;//外观对象需要清楚具体的子系统功能
private facade(){//私有构造函数
arr=new HashSet<dish>();
arr.add(new ConcreteDish("冬瓜排骨"));
arr.add(new ConcreteDish("糖醋里脊"));
arr.add(new ConcreteDish("宫保鸡丁"));
arr.add(new ConcreteDish("青笋肉丝"));
arr.add(new ConcreteDish("椒盐蘑菇"));
}
public static AbstractFacade getInstance(){//返回单例对象
return server;
}
public void meal(List<String> list){//向客户端提供的功能调用
/*
Iterator中只有hasNext、next和remove方法,不晓得为什么不增加一个
还原的从头开始再次遍历的操作,无非就是修改一下cursor的下标
*/
Iterator<dish> it=null;
dish d=null;
for(String s:list){
it=arr.iterator();
while(it.hasNext()){
d=it.next();
if(d.getName().equals(s)){
d.get();
break;
}
}
}
}
}
interface dish{//抽象子系统功能,可以没有,无所谓
void get();
String getName();
}
class ConcreteDish implements dish{//具体子系统
private String name;
public ConcreteDish(String name){
this.name=name;
}
public void get(){
System.out.println(this.name+" is take up");
}
public String getName(){
return this.name;
}
}
总结
外观模式提供的功能就是分离耦合度较高的两个部分,一般可以说成是功能调用发起方和一个复杂子系统之间,在两者之间引入外观对象,降低耦合度并提供重用性,基于扩展考虑,又在结构中添加抽象外观类。