结构性模式之---外观模式、MyBatis中Configuration的外观模式的使用分析

本文涉及的产品
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
简介: 结构性模式之---外观模式、MyBatis中Configuration的外观模式的使用分析

前言

  • 通过一个影院管理项目来了解外观模式

影院管理项目

组建一个家庭影院 :

DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,其过程为: 直接用遥控器:统筹各设备开关

开爆米花机

放下屏幕

开投影仪

开音响

开 DVD,选 dvd

去拿爆米花

调暗灯光

播放

观影结束后,关闭各种设备

传统方式解决影院管理

image.png

传统方式解决影院管理问题分析

1)在ClientTest的main方法中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程。

2)不利于在ClientTest中,去维护对子系统的操作。

3)解决思路 :定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口提供四个方法ready,play,pause,end),用来访问子系统中的一群接口

4)也就是说,通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关系这个系统的内部细节 => 外观模式

外观模式基本介绍

1)外观模式(Facade),也叫“过程模式”:外观模式为子系统中的一组接口提供一个一致的界面,此模式定义类一个高层接口,这个接口使得这一子系统更加容易使用

2)外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节

外观模式原理类图

image.png

类图说明 :

1)外观类(Facade):为调用端提供统一的调用接口,外观类知道那些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象

2)调用者(Client):外观接口的调用者

3)子系统的集合 :指模块或者子系统,处理Facade对象指派的任务,他是功能的实际提供者。

外观模式解决影院管理

1)外观模式可以理解为转换一群接口,客户只要调用一个接口,而不用调用多个接口才能达到目的。比如 :在pc上安装软件的时候经常有一键安装选项(等等),还有手机重启功能(把关机和启动合为一个操作)。

2)外观模式就是解决多个复杂接口带来的使用困难,起到简化用户操作的作用。

具体实现

image.png

package java设计模式.Facade;

public class DVDPlayer {
    //使用单例模式, 使用饿汉式
    //类的内部创建对象
   private final static DVDPlayer instance=new DVDPlayer();
   private DVDPlayer(){

   }
   //向外提供一个静态公共方法
    public static DVDPlayer getInstance(){
       return instance;
    }
    //开启
    public void on() {
        System.out.println("DVD开始运行");
    }
    //关闭
    public void off() {
        System.out.println("DVD关闭");
    }
    //运行
    public void play() {
        System.out.println("DVD正在运行");
    }

    //DVD放完了
    public void pause() {
        System.out.println("DVD放完了");
    }



}
package java设计模式.Facade;
//爆米花机
public class Popcorn {
    private Popcorn(){

    }
    private final static Popcorn instance=new Popcorn();
    public static Popcorn getInstance(){
        return instance;
    }
    //爆米花机开机
    public void on() {
        System.out.println("爆米花机开机");
    }
    //爆米花机关机
    public void off() {
        System.out.println("爆米花机关机");
    }
    //爆米花机正在制作爆米花
    public void pop() {
        System.out.println("爆米花机正在制作爆米花");
    }

}
package java设计模式.Facade;

public class Projector {
    //创建投影机
    private static Projector instance = new Projector();

    public static Projector getInstance() {
        return instance;
    }
    //投影机开机
    public void on() {
        System.out.println("投影机开机");
    }
    //投影机关机
    public void off() {
        System.out.println("投影机关机");
    }
    //投影机正在运行
    public void focus() {
        System.out.println("投影机正在运行");
    }


}
package java设计模式.Facade;

public class Screen {
    //创建荧幕
    private static Screen instance = new Screen();

    public static Screen getInstance() {
        return instance;
    }

    //上升荧幕
    public void up() {
        System.out.println("上升荧幕");
    }
    //下降荧幕
    public void down() {
        System.out.println("下降荧幕");
    }

}
package java设计模式.Facade;

public class Stereo {
    //创建立体声机
    private static Stereo instance = new Stereo();

    public static Stereo getInstance() {
        return instance;
    }
    //立体声机开机
    public void on() {
        System.out.println("立体声机开机");
    }
    //立体声机关机
    public void off() {
        System.out.println("立体声机关机");
    }
    //立体声机正在运行
    public void up() {
        System.out.println("立体声机正在运行");
    }

}
package java设计模式.Facade;
//灯光
public class TheaterLight {
    //创建灯光
    private static TheaterLight instance = new TheaterLight();

    public static TheaterLight getInstance() {
        return instance;
    }
    //灯光开启
    public void on() {
        System.out.println("灯光开启");
    }
    //灯光关闭
    public void off() {
        System.out.println("灯光关闭");
    }
    //灯光调暗
    public void dim() {
        System.out.println("灯光调暗");
    }
    //灯光调亮
    public void bright() {
        System.out.println("灯光调亮");
    }

}
package java设计模式.Facade;
//外观类
public class HomeTheaterFacade {
    //定义各个子系统对象
    private TheaterLight theaterLight;
    private Popcorn popcorn;
    private Stereo stereo;
    private Projector projector;
    private Screen screen;
    private DVDPlayer dVDPlayer;


    //构造器
    public HomeTheaterFacade() {
//        super();
        this.theaterLight = TheaterLight.getInstance();
        this.popcorn = Popcorn.getInstance();
        this.stereo = Stereo.getInstance();
        this.projector = Projector.getInstance();
        this.screen = Screen.getInstance();
        this.dVDPlayer = DVDPlayer.getInstance();
    }

    //操作分成 4 步
    //电影院准备
    public void ready() {
        popcorn.on();
        popcorn.pop();
        screen.down();
        projector.on();
        stereo.on();
        dVDPlayer.on();
        theaterLight.dim();
    }
    //电影开始
    public void play() {
        dVDPlayer.play();
    }
    //电影结束
    public void pause() {
        dVDPlayer.pause();
    }
    //电影院关闭
    public void end() {
        popcorn.off();
        theaterLight.bright();
        screen.up();
        projector.off();
        stereo.off();
        dVDPlayer.off();
    }


}
package java设计模式.Facade;

public class Client {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //这里直接调用。。 很麻烦
        HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
        //电影院准备
        homeTheaterFacade.ready();
        //电影院开始
        homeTheaterFacade.play();
        //电影院结束
        homeTheaterFacade.end();
    }
}

image.png

Configuration源码结构分析

1、类图分析

image.png

 下面我们看看Mybatis的源码来具体理解外观模式。

public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory);
}

上述代码其实是完成一个创建MetaObject的事情,但是它是将一个负责创建MetaObject的子系统放在了这个方法里面。为什么要这么做?实际上如果直接让我们应用层去使用MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory);这个方法。可以看出参数实在太多,而Configuration类使用外观模式,外观类并不具体实现什么,他只是负责调用和管理子系统

下面看看configuration中的构造器 可以把上面的objectFactory,objectWrapperFactory,reflectorFactory看作三个子系统

接下来到MetaObject的里面看看forObject方法

public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
return object == null ? SystemMetaObject.NULL_META_OBJECT : new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}

对应的构造函数

可以看出这个MetaObject也是个将构造器私有的特殊单例模式

private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper)object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
this.objectWrapper = new MapWrapper(this, (Map)object);
} else if (object instanceof Collection) {
this.objectWrapper = new CollectionWrapper(this, (Collection)object);
} else {
this.objectWrapper = new BeanWrapper(this, object);
}

}

总结

外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性

外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展

通过合理的使用外观模式,可以帮我们更好的划分访问的层次

当系统需要进行分层设计时可以考虑使用外观模 式

在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个外观类,来提供遗留系统的比较清晰简单的接口,让新系统与外观类交互, 提高复用性

不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好,要以让系统有层次,利于维护为目的 。


相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
相关文章
|
7月前
|
SQL XML Java
|
7月前
|
Java 数据库连接 mybatis
mybatis 框架分析——mybatis框架使用篇
mybatis 框架分析——mybatis框架使用篇
38 0
|
7月前
|
druid Java 数据库连接
SpringBoot原理分析 | Spring Data整合:JDBC、Druid、Mybatis
SpringBoot原理分析 | Spring Data整合:JDBC、Druid、Mybatis
142 0
|
7月前
|
SQL Java 数据库连接
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
869 0
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
|
3月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
4月前
|
SQL Java 数据库连接
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
文章讲述了在使用Mybatis时遇到的资源文件找不到的问题,并提供了通过修改Maven配置来解决资源文件编译到target目录下的方法。
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
|
5月前
|
Java 数据库连接 mybatis
mybatis包扫描环境分析,最简单的环境准备
mybatis包扫描环境分析,最简单的环境准备
|
5月前
|
Java 数据库连接 Maven
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
|
7月前
|
SQL Java 数据库连接
日志输出-查看 SQL:深入分析 MyBatis 执行过程
日志输出-查看 SQL:深入分析 MyBatis 执行过程
250 0
|
7月前
|
Java 关系型数据库 数据库连接
MyBatis 执行流程分析
MyBatis 执行流程分析
60 2