设计模式之门面模式

90 阅读3分钟

案例:写信

写信的步骤:

  1. 写信的内容
  2. 写信封
  3. 把信放到信封中
  4. 投递到信箱中

类图:

代码实现:

/**
 * @Description: 定义写信的过程
 */
public interface LetterProcess {

    /**
     * 写信
     * @param context 信的内容
     */
    void writeContext(String context);

    /**
     * 写信封
     * @param address 收件人地址
     */
    void fillEnvelope(String address);

    /**
     * 把信装进信封
     */
    void letterIntoEnvelope();

    /**
     * 邮寄
     */
    void sendLetter();

}

/**
 * @Description: 写信过层的具体实现
 */
public class LetterProcessImpl implements LetterProcess {

    @Override
    public void writeContext(String context) {
        System.out.println("写信的内容:" + context);
    }

    @Override
    public void fillEnvelope(String address) {
        System.out.println("写信封收件人地址:" + address);
    }

    @Override
    public void letterIntoEnvelope() {
        System.out.println("把信装到信封中...");
    }

    @Override
    public void sendLetter() {
        System.out.println("邮寄信件...");
    }
}

/**
 * @Description: 写信主程序
 */
public class Client {

    public static void main(String[] args) {

        LetterProcess letterProcess = new LetterProcessImpl();

        // 1. 写信的内容
        letterProcess.writeContext("亲爱的李华,您好!");
        // 2. 写信封收件人地址
        letterProcess.fillEnvelope("幸福路88号");
        // 3. 把信装进信封中
        letterProcess.letterIntoEnvelope();
        // 4. 邮寄信件
        letterProcess.sendLetter();

    }

}

问题:主程序必须调用写信的所有步骤而且调用顺序不能乱

改进后的类图:

这就是门面模式,由于 Sub System 业务逻辑比较复杂,为了让调用者可以简单地使用,就对 Sub System 进行了封装,增加一个门面,Client 调用时,直接调用门面的方法而不用了解具体的实现方法以及相关的业务顺序。

增加的 ModenPostOffice 类:

/**
 * @Description: 写信的门面类
 */
public class ModenPostOffice {

    private LetterProcess letterProcess = new LetterProcessImpl();

    /**
     * 写信方法的封装
     * @param context 信的内容
     * @param address 地址
     */
    public void sendLetter(String context, String address) {
        letterProcess.writeContext(context);
        letterProcess.fillEnvelope(address);
        letterProcess.letterIntoEnvelope();
        letterProcess.sendLetter();
    }

}

Client 调用:

/**
 * @Description: 写信主程序
 */
public class Client {

    public static void main(String[] args) {

        ModenPostOffice postOffice = new ModenPostOffice();

        String context = "亲爱的李华,你好!";
        String address = "幸福路88号";

        postOffice.sendLetter(context, address);

    }

}

经过改造,客户端的调用变得简单很多,系统的扩展性也有很大提高。比如扩展业务:邮件信件之前必须进行安全检查,增加一个类,用于检查信件,类图如下:

代码变化:

/**
 * @Description:
 */
public class Police {

    public void checkLetter(LetterProcess letterProcess) {
        System.out.println("检查信件...");
    }

}

/**
 * @Description: 写信的门面类
 */
public class ModenPostOffice {

    private LetterProcess letterProcess = new LetterProcessImpl();
    private Police police = new Police();

    /**
     * 写信方法的封装
     * @param context 信的内容
     * @param address 地址
     */
    public void sendLetter(String context, String address) {
        letterProcess.writeContext(context);
        letterProcess.fillEnvelope(address);
        // 装入信封之前,检查信件
        police.checkLetter(letterProcess);
        letterProcess.letterIntoEnvelope();
        letterProcess.sendLetter();
    }

}

增加了一个 letterPolice 变量的声明以及一个方法的调用,就在写信的过程中增加了新的业务逻辑,对于客户端来说是无感知的,客户端调用没有任何变化,客户端不知道也不必要知道增加了新的业务逻辑。

这就是门面模式,如果子系统的业务逻辑比较复杂,就可以封装出一个或多个门面出来,使的项目的结构简单且扩展性好。在大型项目中,也经常使用这种模式,将某个人负责的独立的模块封装到一个门面中,这样项目组其他成员不需要了解每个模块的具体实现,对项目整体质量的提升也有帮助。

本文原书:《您的设计模式》作者:CBF4LIFE