设计模式之结构模式(二)

版权声明:欢迎转载评论~哈哈哈哈请标明出处呀 https://blog.csdn.net/legendaryhaha/article/details/88781466

外观(门面模式)

设计模式之结构模式(一)


定义

外观模式通过提供了一个统一的高层的接口,用来访问子系统中的一群接口。这个模式和我们先前说的基本模式中的接口模式的形式上类似,但外观模式更强调从一个系统的高层次上来设计接口而不是简单的低层次的方法包装。


图例

外观模式也成为门面模式,它是用来解决客户端和子系统的松散耦合的问题的,如图:
在这里插入图片描述
由于一个大的项目下,存在着若干模块,模块和模块之间有组层一个子系统,而客户端在模块上可耦合度较低,但当模块与模块之间组层一个子系统时,则可能出现上图的情况,一个客户依赖着多个类,这样带来的影响是:

  • 类层次结构(子系统)不再对客户端透明,子系统的的修改,或者功能拓展,客户端都需要跟着变化。
  • 客户端直接和系统组成聚合关系

于是外观模式建议从高层上定义一个外观接口(请注意,不要和我们Java的interface联系在一起),充当客户端访问子系统时的掮客:
在这里插入图片描述

通过上图,我们可以发现,现在是Facade外观(接口)和子系统组合成聚合关系,客户端和子系统关系也不再交纵错杂,而是统一依赖外观接口。

外观模式也诠释了面向对象设计原则中的最少知识原则,即一个类应该只跟它需要打交道的类沟通,多余的方法不要,这样可以有效的保证松散耦合。

小结

从上图我们可以看到,门面模式中,包含着三个角色:

  1. 门面角色(facade):外观模式的核心。它被客户角色调用,熟悉子系统的功能,内部根据客户角色的需求预定了几种功能的组合。
  2. 子系统角色:实现了子系统的功能。它对客户角色和Facade是未知的,为了隐藏细节,不然外界所知,既满足依赖倒置原则,它内部可以有系统内的相互交互,也可以有供外界调用的接口。这也是我们文章一开始强调的从高层创建接口和其他简单创建接口的程序的区别。
  3. 客户角色:通过依赖倒置,我们的客户角色现在只需通过facede就能实现的功能。

例子

应用场景:一个客户表单数据要保存到数据中,这个表单包含地址验证模块,客户手机号码验证模块,信用卡验证模块,只有都验证成功,我们才能将数据保存到数据库中。

从以上的应用中,我们可以分析出客户分别依赖地址、手机、信用卡三个模块。如果是这中方式设计:我先进行地址验证if 成功,then执行下一个…

上面这种方式,无意将细节过分的暴露给客户端了,于是,在外观模式中,有如下改进:

子系统,这里每个子系统只有一个类,实际开发,可能不止

package com.fang.facade;

public class AddressValid {
    public boolean valid(String src){
        System.out.println("采用正则验证地址"+src);
        return true;
    }
}
public class CreditValid {
    public boolean valid (String src){
        System.out.println("采用XX验证了信用卡"+src);
        return true;
    }
}
public class TelValid {
    public boolean valid(String src){
        System.out.println("采用字符串验证了电话号码"+src);
        return true;
    }
}

门面Facade,这里重申一次,我们的设计模式是不依赖与任何一门语言的,我们总说门面模式提供一个可供客户端统一操作的高层接口,但此接口决不能轻易就代入到Java里的interface,它实际上是一个class,所谓的接口是一个对外提供访问的方法:

public class Facade {
    private AddressValid addressValid;
    private CreditValid creditValid;
    private TelValid telValid;

    /**
     * 其实这里设置也不是很好,最好可以像那些框架那样
     * 要用时才初始化通过反射实现,或者将初始化搬入到
     * 局部方法中isValid
     */
    public Facade(){
        addressValid = new AddressValid();
        creditValid = new CreditValid();
        telValid = new TelValid();
    }
    /**
     * 这里我们可以通过get和set设置子系统相应的
     * 属性的值,譬如客户端提交数据后,将它们的
     * 各字段填充到各个属性中
     */
    public boolean isValid(){
        boolean addressisValid=addressValid.valid("这个字符串本来应该在set后get到的");
        boolean creditisValid = creditValid.valid("45789963XXXXX");
        boolean telisValid = telValid.valid("152XXXXXXX");
        if(!addressisValid) {
            System.out.println("地址出错");
            return false;
        }
        if(!creditisValid) {
            System.out.println("信用卡出错");
            return false;
        }
        if(!telisValid) {
            System.out.println("电话号码出错");
            return false;
        }
        return true;
    }
}

最后,客户端只需要通过Facade就可以和子系统各部分打交道了。


总结

通过门面模式,我们将更多的细节隐藏了起来,这也是遵循依赖倒置原则,从而降低耦合。

猜你喜欢

转载自blog.csdn.net/legendaryhaha/article/details/88781466