外观模式(Facade pattern),又叫门面模式,作用是为一组复杂的方法调用提供一个统一的调用方法,在这个方法中来实现这组方法的复杂调用。
比如我们有一个功能,要依次调用A、B、C、D、E 5个方法,这时又有其他几个功能都要这样调用,哪每个功能都要自己写一遍如下类似代码:
void call() {
A();
B();
C();
D();
E();
}
哪个功能来调用这个逻辑,就要这样写一遍,各个功能的调用处就显得臃肿且复杂。
这时我们就需要一个方法来简化各个调用方的代码和逻辑,让调用方只关心我调用的功能是不是我需要的结果。
外观模式就登场了,外观模式为一个功能提供一个统一的方法,而不需要调用方去组织被调用方的各种业务逻辑,让调用方的使用更加简单,同时也让调用方和被调用方的逻辑解耦。
我们今天就以做菜:炒西红柿为例子,来演示代码。
炒西红柿这道菜挺简单,大家基本都会做,大概的流程是:
1、准备食材,准备鸡蛋(打鸡蛋),洗西红柿,切西红柿等;
2、炒鸡蛋;
3、炒西红柿;
4、把西红柿和鸡蛋合炒;;
5、加糖;
6、加盐;
7、盛盘上菜。
我们炒西红柿的流程大概如上,步骤其实还挺多(当然每个人的步骤和做法可能稍微有出入),我要自己炒一个就要逐步晚上上面的步骤,外观模式的作用就好比,我不自己做了,我直接下馆子或是点外卖,饭馆相当于给我提供了一个接口,让我调用一下,稍等几分钟,菜就好了,中间的各个环节,对我来说我不用去关心了,这就是外观模式的意义。
我们来看代码。
1、西红柿炒鸡蛋的抽象定义
package com.itzhimei.study.design.facade;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public interface IScrambledEggWithTomato {
/**
* 准备食材:鸡蛋和西红柿
*/
void prepare();
/**
* 炒鸡蛋
*/
void scrambledEgg();
/**
* 炒西红柿
*/
void scrambledTomato();
/**
* 合起来炒
*/
void scrambledEggWithTomato();
/**
* 调味:加糖
*/
void addSugar();
/**
* 调味:加盐2
*/
void addSalt();
/**
* 盛盘上菜
*/
void finish();
}
2、西红柿炒鸡蛋的具体实现
package com.itzhimei.study.design.facade;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class ScrambledEggWithTomato implements IScrambledEggWithTomato {
@Override
public void prepare() {
System.out.println("准备食材:鸡蛋和西红柿");
}
@Override
public void scrambledEgg() {
System.out.println("炒鸡蛋");
}
@Override
public void scrambledTomato() {
System.out.println("炒西红柿");
}
@Override
public void scrambledEggWithTomato() {
System.out.println("合起来炒");
}
@Override
public void addSugar() {
System.out.println("调味:加糖");
}
@Override
public void addSalt() {
System.out.println("调味:加盐");
}
@Override
public void finish() {
System.out.println("盛盘上菜");
}
}
3、外观模式 抽象定义
package com.itzhimei.study.design.facade;
/**
* @Auther: www.itzhimei.com
* @Description: 外观模式 抽象定义
*/
public interface ICookFacade {
void cookScrambledEggWithTomato();
}
4、外观模式 实现
package com.itzhimei.study.design.facade;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class CookFacade implements ICookFacade {
IScrambledEggWithTomato scrambledEggWithTomato;
public CookFacade(IScrambledEggWithTomato scrambledEggWithTomato) {
this.scrambledEggWithTomato = scrambledEggWithTomato;
}
@Override
public void cookScrambledEggWithTomato() {
scrambledEggWithTomato.prepare();
scrambledEggWithTomato.scrambledEgg();
scrambledEggWithTomato.scrambledTomato();
scrambledEggWithTomato.scrambledEggWithTomato();
scrambledEggWithTomato.addSugar();
scrambledEggWithTomato.addSalt();
scrambledEggWithTomato.finish();
}
}
5、测试
package com.itzhimei.study.design.facade;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class Client {
public static void main(String[] args) {
IScrambledEggWithTomato scrambledEggWithTomato = new ScrambledEggWithTomato();
ICookFacade cookFacade = new CookFacade(scrambledEggWithTomato);
cookFacade.cookScrambledEggWithTomato();
}
}
输出
准备食材:鸡蛋和西红柿
炒鸡蛋
炒西红柿
合起来炒
调味:加糖
调味:加盐
盛盘上菜
类关系图:
最后要说的一点,外观模式看起来和模板方法模式很像,区别在于,模板方法模式的模板方法中引用的方法都是抽象的,需要子类去实现,这给了子类可按照自己的需要进行变化的灵活性。
而外观模式简化了调用者的处理逻辑,并且外观模式的外观方法,和外观方法调用的方法,都是已经实现的具体逻辑,其重点在于简化调用者的调用逻辑。