设计模式(六)—— 门面

122 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

概念

门面模式(Facade)是一种结构型设计模式,它能将多个不同的子系统接口封装起来,并对外提供统一的高层接口,使复杂的子系统变得更易使用。

无论是“门”还是“面”,指代的都是某系统的外观部分,也就是与外界接触的临界面或接口,所以门面模式常常也被翻译为“外观模式”

实例演示

注:本文内容参考 《秒懂设计模式》一书,本文对其做了概括凝练,主要是为了自身学习使用,如果无法理解,建议查看原书。

傻瓜相机其实是一个很好的例子用于解释门面模式。

早期的相机使用起来是非常麻烦的,拍照前总是要根据场景情况进行一系列复杂的操作,如对焦、调节闪光灯、调光圈等,非专业人士面对这么一大堆的操作按钮根本无从下手,拍出来的照片质量也不高。

而对于傻瓜相机来说,用户再也不必学习那些复杂的参数调节了,只要按下快门键就可完成所有操作。

即 傻瓜相机把复杂的功能都隐藏在内部,最终只为外接提供一个简单方便的快门按键,让用户能够一键操作。  这就是门面模式的精髓。

对于门面模式在日常工作中的具体应用,我们还是举一个简单的例子来演示下。既然是门面模式,那么我们就以商铺门面来举例。

1. 亲自下厨(内部流程)

假设小明同学想要亲自下厨做饭,但因不会做菜所以请妹妹帮忙。我们将步骤简化为以下 3 步,首先小明找菜贩买菜,然后找妹妹做菜,最后亲自洗碗。

首先小明需要去找菜贩买菜,代码如下:

public class VegVendor {

    public void purchase(){
        System.out.println("供应蔬菜……");
    }

}

然后小明需要找妹妹来帮忙做饭,代码如下:

public class Helper {

    public void cook(){
        System.out.println("下厨烹饪……");
    }

}

最后小明作为客户端类开始吃饭并洗碗,代码如下:

public class Client{

    public void eat(){
        System.out.println("开始用餐……");
    }

    public void wash(){
        System.out.println("洗碗……");
    }

    public static void main(String[] args) {
        //找蔬菜商买菜
        VegVendor vegVendor = new VegVendor();
        vegVendor.purchase();
        //找妹妹下厨
        Helper sister = new Helper();
        sister.cook();
        //客户端用餐
        Client client = new Client();
        client.eat();
        //最后还得洗碗,确实有点麻烦
        client.wash();
    }
}

2. 去餐厅吃饭(提供门面方法)

虽然上面的代码不复杂,但是一整套流程下来还是很累人,如果烹饪方法再复杂些,或者是客户端对各个子系统的操作不当,那么就可能会出现更大的问题。

这是,小明开始意识到,任何事都亲力亲为的做法可能并不合适,专业的事情还是应该交给专业的人去完成,他们会把这些子系统的操作过程封装起来,再以更为便捷的方式提供给用户使用。

于是,小明决定了,去餐厅吃饭!!!!!

餐厅的工作流程如下:

public class Facade {

    private VegVendor vegVendor;
    private Chef chef;
    private Waiter waiter;
    private Cleaner cleaner;

    public Facade() {
        this.vegVendor = new VegVendor();
        //开门前就找蔬菜商准备好蔬菜
        vegVendor.purchase();
        //雇佣厨师
        this.chef = new Chef();
        //雇佣服务员
        this.waiter = new Waiter();
        //雇佣清洁工、洗碗工等
        this.cleaner = new Cleaner();
    }

    public void order(){
        //接待,入座,点菜
        waiter.order();
        //找厨师做饭
        chef.cook();
        //上菜
        waiter.serve();
        //收拾桌子,洗碗,以及其他操作
        cleaner.clean();
        cleaner.wash();
    }
}

餐厅里封装了大量的子系统资源,如蔬菜商、厨师、服务员、洗碗工等,并且对各个子系统依次进行了初始化操作。

而小明只需要调用 order() 方法就可以享受现成可口的饭菜了,操作变得简单而优雅。

总结

门面模式不但重要,而且其应用也非常广泛,最常见的是在我们日常工作开发中对多表更新操作,而且多表更新需要在一个事务里面进行。我们只需要对这些更新操作封装成一个 update 方法即可。如此一来,上层方法只需要调用这个 update 方法就可以进行更新了。

门面模式的各角色定义如下:

  • Facade(外观门面):封装了多个子系统,并将它们整合起来对外提供统一的访问接口。
  • SubSystemA、SubSystemB、SubSystemC(子系统 A、子系统 B、子系统 C):隐藏于门面中的子系统,数量任意,且对外部不可见。对应本章例程中的蔬菜商类、厨师类、服务员类等。
  • Client(客户端):门面系统的使用方,只访问门面提供的接口。

参考文档

  • 《秒懂设计模式》—— 刘韬