深入浅出外观模式

外观模式介绍

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。

外观模式结构图:

(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。

(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

案例场景

场景一:自己泡茶,整个过程应该是“烧开水->拿茶具->泡茶叶”然后喝茶。

定义一个饮用水类:DrinkableWater

/**
 * 烧水
 */
public class DrinkableWater {

    public DrinkableWater(){
        System.out.println("水准备好了");
    }

    //烧水
    public void facadeWater(){
        System.out.println("水烧开了");
    }
}
复制代码

定义一个茶叶类:Tea

/**
 * 茶叶
 */
public class Tea {

    public Tea(){
        System.out.println("茶叶准备好了");
    }

    //取茶
    public void facadeTea(){
        System.out.println("可以泡茶了");
    }
}
复制代码

定义一个茶杯类:TeaCup

/**
 * 茶杯
 */
public class TeaCup {

    public TeaCup(){
        System.out.println("茶杯准备好了");
    }

    //泡茶
    public void facadeTeaCup(Tea tea){
        tea.facadeTea();
        System.out.println("茶叶泡进茶杯了");
        System.out.println("茶冲好了");
    }
}
复制代码

准备就绪,开始泡茶

public static void main(String[] args) {
    System.out.println("准备泡茶...");
    DrinkableWater drinkableWater = new DrinkableWater();
    TeaCup teaCup = new TeaCup();
    Tea tea = new Tea();

    drinkableWater.facadeWater();
    teaCup.facadeTeaCup(tea);
    System.out.println("喝茶...");
}
复制代码

运行结果

准备泡茶...
水准备好了
茶杯准备好了
茶叶准备好了
水烧开了
可以泡茶了
茶叶泡进茶杯了
茶冲好了
喝茶...
复制代码

场景二:去茶馆喝茶,不用自己动手泡茶了,直接告诉茶馆的服务员就行了。

定义一个服务员类:

/**
 * 服务员
 */
public class Waiter {

    private DrinkableWater drinkableWater = new DrinkableWater();
    private TeaCup teaCup = new TeaCup();
    private Tea tea = new Tea();

    //获得一杯茶
    public void getTea(){
        drinkableWater.facadeWater();
        teaCup.facadeTeaCup(tea);
    }
}
复制代码

客户类:Customer

public class Customer {

    public static void main(String[] args) {
        //叫店小二
        Waiter waiter = new Waiter();
        //从店小二那获得一杯茶
        waiter.getTea();
    }
}
复制代码

运行结果

水准备好了
茶杯准备好了
茶叶准备好了
水烧开了
可以泡茶了
茶叶泡进茶杯了
茶冲好了
复制代码

在上面的泡茶的例子中,客人就是客户角色,茶馆服务员就是门面角色,茶具、饮用水、茶叶就是子系统角色。

代码看上去都很简单,也许你感觉二者区别不是很大,假如在软件开发中三个子系统之间有先后顺序,还有来自不同网络开销,我们通过门面模式提供的方法,就屏蔽了这些差异,让我们只需要调用门面角色提供给我们的方法即可。

外观模式优缺点

优点

(1)减少系统的相互依赖

如果我们不使用门面模式, 外界访问直接深入到子系统内部, 相互之间是一种强耦合关系, 你死我就死, 你活我才能活, 这样的强依赖是系统设计所不能接受的, 门面模式的出现就很好地解决了该问题, 所有的依赖都是对门面对象的依赖, 与子系统无关。

(2)提高安全性

想让你访问子系统的哪些业务就开通哪些逻辑, 不在门面上开通的方法, 你休想访问到。

缺点

(1)不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。

(2)如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。

外观模式应用场景

(1)解决易用性问题

门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。

(2)解决性能问题

通过将多个接口调用替换为一个门面接口调用,减少网络通信成本,提高客户端的响应速度。

(3)解决分布式事务问题

需要调用多个子系统的接口方法,而这些接口要么都成功,要么都失败,我们就可以利用门面模式包裹这些子系统接口,然后通过某种方法保证这些接口在一个事务中完成。

总结

在几乎所有的软件中都能够找到外观模式的应用,如绝大多数B/S系统都有一个首页或者导航页面,大部分C/S系统都提供了菜单或者工具栏,在这里,首页和导航页面就是B/S系统的外观角色,而菜单和工具栏就是C/S系统的外观角色,通过它们用户可以快速访问子系统,降低了系统的复杂程度。所有涉及到与多个业务对象交互的场景都可以考虑使用外观模式进行重构。

很多时候不是设计模式没有用,而是自己编程开发经验不足导致即使学了设计模式也很难驾驭。毕竟这些知识都是经过一些实际操作提炼出来的精华。

作者:初念初恋
链接:https://juejin.cn/post/7223417872596516924

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值