外观模式说,也叫门面模式,这个模式简单也简单,说复杂也复杂。简单是因为,外观模式很好理解,有可能你已经用到过这个模式,只是你还不知道这个是外观模式。说复杂是因为外观模式是为了将复杂的逻辑封装起来,向外暴露出一个/多个简单的接口供使用者使用,而这个“复杂的逻辑”根据实际情况会有不同的难度。
一、定义
为子系统提供若干个接口,外观模式提供一个高层级的接口,外界只需调用高层接口,就可以实现子系统若干接口的逻辑。而高层接口的使用者无需关心这若干个子系统做了什么。
大白话:使用者只关心自己做什么,然后得到想要的结果,并不关心中间做了什么。
UML:
Facade:系统对外的统一接口
SystemA/B/C:子系统接口
二、使用场景
1、为一个复杂的子系统提供一个简单的接口。子系统往往因为不断的演化二变得越来越复杂,或者被替换,而Facade可以提供一个统一的接口,对外隐藏子系统的变化。
2、当你需要构建一个层次结构的子系统时,而子系统间又有相互依赖时,可以使用Facade定义每层的入口点,仅通过Facade进行通信,从而简化了子系统间的依赖关系。
举个场景栗子:现在比较流行订餐送餐,比如X团,X了么,X度外卖······我现在想要订餐,那么我需要做的是:下单——吃饭,就这么简单。而中间可能有许许多多复杂的过程,并没有暴露给你,比如:下单——餐馆接单——餐馆做饭——餐馆将食物打包——叫来送餐骑手——骑手取餐——骑手送餐——半路车胎扎了——补车胎——继续送餐到你手里——吃饭,我们需要把中间复杂的过程,对使用者只暴露一个“下单”的接口,下单后自动完成中间的过程。
三、示例
首先,把子系统的主接口定义好:
/**
* 超类
*/
public abstract class Work {
public abstract void doSomething();
}
接下来,定义若干个子系统接口:
/**
* 餐馆接单
*/
public class TakeOrder extends Work {
@Override
public void doSomething() {
System.out.println("餐馆接单,接到一份鱼香肉丝盖饭!");
}
}
/**
* 餐馆做饭
*/
public class Cook extends Work {
@Override
public void doSomething() {
System.out.println("餐馆做饭,做一份鱼香肉丝盖饭!");
}
}
/**
* 餐馆打包食物
*/
public class PackFood extends Work {
@Override
public void doSomething() {
System.out.println("餐馆打包食物,打包一份鱼香肉丝盖饭!");
}
}
/**
* 餐馆叫来一个送餐员
*/
public class CallMan extends Work {
@Override
public void doSomething() {
System.out.println("餐馆叫来一个送餐员!");
}
}
/**
* 送餐员取餐
*/
public class TakeFood extends Work {
@Override
public void doSomething() {
System.out.println("送餐员取餐,取到一份鱼香肉丝盖饭!");
}
}
/**
* 送餐员送餐
*/
public class DeliveryFood extends Work {
@Override
public void doSomething() {
System.out.println("送餐员送餐,一份鱼香肉丝盖饭!");
}
}
/**
* 送餐员车胎扎了
*/
public class TyresTiepUp extends Work {
@Override
public void doSomething() {
System.out.println("送餐员车胎扎了!");
}
}
/**
* 送餐员补车胎
*/
public class FixTyres extends Work {
@Override
public void doSomething() {
System.out.println("送餐员补车胎!");
}
}
/**
* 送餐员继续送餐
*/
public class DeliveryFood2 extends Work {
@Override
public void doSomething() {
System.out.println("送餐员继续送餐,一份鱼香肉丝盖饭!");
}
}
够多,够复杂!但是作为你,你并不关心上面那些流程,毕竟是花了钱的,只管下单:
public class XTuan {
/**
* 下单
*/
public void placeOrder() {
//餐馆接单
TakeOrder takeOrder = new TakeOrder();
//餐馆做饭
Cook cook = new Cook();
//餐馆将食物打包
PackFood packFood = new PackFood();
//叫来送餐骑手
CallMan callMan = new CallMan();
//骑手取餐
TakeFood takeFood = new TakeFood();
//骑手送餐
DeliveryFood deliveryFood = new DeliveryFood();
//半路车胎扎了
TyresTiepUp tyresTiepUp = new TyresTiepUp();
//补车胎
FixTyres fixTyres = new FixTyres();
//继续送餐到你手里
DeliveryFood2 deliveryFood2 = new DeliveryFood2();
takeOrder.doSomething();
cook.doSomething();
packFood.doSomething();
callMan.doSomething();
takeFood.doSomething();
deliveryFood.doSomething();
tyresTiepUp.doSomething();
fixTyres.doSomething();
deliveryFood2.doSomething();
}
}
我们关心的只是下载了外卖,然后订餐,然后吃:
public static void main(String[] args) {
//实例化一个X团外卖
XTuan xt = new XTuan();
System.out.println("下单啦~下一份鱼香肉丝吧!");
xt.placeOrder();
System.out.println("餐到手,可以吃了!");
}
log:
12-21 15:51:23.470 29104-29104/? I/System.out: 下单啦~下一份鱼香肉丝吧!
12-21 15:51:23.470 29104-29104/? I/System.out: 餐馆接单,接到一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 餐馆做饭,做一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 餐馆打包食物,打包一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 餐馆叫来一个送餐员!
12-21 15:51:23.470 29104-29104/? I/System.out: 送餐员取餐,取到一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 送餐员送餐,一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 送餐员车胎扎了!
12-21 15:51:23.470 29104-29104/? I/System.out: 送餐员补车胎!
12-21 15:51:23.470 29104-29104/? I/System.out: 送餐员继续送餐,一份鱼香肉丝盖饭!
12-21 15:51:23.470 29104-29104/? I/System.out: 餐到手,可以吃了!
当然,这只是比较简单的用法,还有更多复杂的场景需要在实际项目中用到,这就需要熟能生巧了