设计模式之 外观模式

外观模式(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();
    }
}

输出

准备食材:鸡蛋和西红柿
炒鸡蛋
炒西红柿
合起来炒
调味:加糖
调味:加盐
盛盘上菜

类关系图:

最后要说的一点,外观模式看起来和模板方法模式很像,区别在于,模板方法模式的模板方法中引用的方法都是抽象的,需要子类去实现,这给了子类可按照自己的需要进行变化的灵活性。

而外观模式简化了调用者的处理逻辑,并且外观模式的外观方法,和外观方法调用的方法,都是已经实现的具体逻辑,其重点在于简化调用者的调用逻辑。