设计模式学习笔记(十七)中介者模式及其应用场景 您所在的位置:网站首页 多重中介模型及其应用 设计模式学习笔记(十七)中介者模式及其应用场景

设计模式学习笔记(十七)中介者模式及其应用场景

2024-07-16 03:03| 来源: 网络整理| 查看: 265

中介者(Mediator)模式指定义了一个单独的中介对象,来封装一组对象之间的交互。即将这组对象之间的交互委派给中介对象,从而来避免对象之间的直接交互。比如我们各种设备之间的通信,就是通过服务器作为中介对象来进行交互:

image-20220407094542645image-20220407094542645一、中介者模式介绍

中介者又叫做调停模式,是一种对象行为型模式,它降低了对象之间的耦合性,让对象易于被独立地调用,是迪米特法则的典型应用,下面就来看看中介者模式的结构和实现:

1.1 中介者模式的结构

中介者模式主要通过引入用于协调其他对象或类之间相互调用的中介者类,为了让系统具有具有更好的灵活性和扩展性。其结构如下图所示:

image-20220407115009351image-20220407115009351

上面的类图中主要包含以下角色:

Mediator:抽象中介者,是中介者的接口/抽象类ConcreteMeditor:中介者的具体实现,实现中介者接口,定义一个List来管理Colleague对象Colleague:抽象同事类,定义同事类的接口/抽象类,保存中介者对象,实现同事类的公共方法ConcreteColleague1、ConcreteColleague2:具体同事类,实现抽象同事类。通过中介者间接完成具体同事类之间的通信交互1.2 中介者模式的实现

根据上面的类图,可以实现如下代码:

抽象中介者及其实现代码语言:javascript复制/** * @description: 中介者抽象类 * @author: wjw * @date: 2022/4/7 */ public abstract class Mediator { /**注册同事类*/ public abstract void register(Colleague colleague); /**处理接收逻辑*/ public abstract void operation(Colleague colleague); } /** * @description: 具体中介者类 * @author: wjw * @date: 2022/4/7 */ public class ConcreteMediator extends Mediator{ private List colleagues = new ArrayList(); @Override public void register(Colleague colleague) { if (!colleagues.contains(colleague)) { colleagues.add(colleague); colleague.setMediator(this); } } @Override public void operation(Colleague colleague) { for (Colleague coll : colleagues) { if (!coll.equals(colleague)) { coll.receive(); } } } }抽象同事类及其实现代码语言:javascript复制/** * @description: 抽象同事类 * @author: wjw * @date: 2022/4/7 */ public abstract class Colleague { protected Mediator mediator; public void setMediator(Mediator mediator) { this.mediator = mediator; } public abstract void receive(); public abstract void send(); } /** * @description: 具体同事类1 * @author: wjw * @date: 2022/4/7 */ public class ConcreteColleague1 extends Colleague{ @Override public void receive() { System.out.println("具体同事类 ConcreteColleague1 接收请求"); } @Override public void send() { System.out.println("具体同事类 ConcreteColleague1 发送请求"); /*中介者进行转发*/ mediator.operation(this); } } /** * @description: 具体同事类2 * @author: wjw * @date: 2022/4/7 */ public class ConcreteColleague2 extends Colleague{ @Override public void receive() { System.out.println("具体同事类 ConcreteColleague2 接收到请求"); } @Override public void send() { System.out.println("具体同事类 ConcreteColleague2 发送请求"); mediator.operation(this); } }客户端测试类代码语言:javascript复制/** * @description: 客户端 * @author: wjw * @date: 2022/4/7 */ public class Client { public static void main(String[] args) { Mediator concreteMediator = new ConcreteMediator(); Colleague concreteColleague1 = new ConcreteColleague1(); Colleague concreteColleague2 = new ConcreteColleague2(); concreteMediator.register(concreteColleague1); concreteMediator.register(concreteColleague2); concreteColleague1.send(); concreteColleague2.send(); } }

测试结果为:

代码语言:javascript复制具体同事类 ConcreteColleague1 发送请求 具体同事类 ConcreteColleague2 接收到请求 具体同事类 ConcreteColleague2 发送请求 具体同事类 ConcreteColleague1 接收请求二、中介者模式应用场景2.1 中介者模式的适用情况

如果遇到以下情况可以考虑使用中介者模式:

系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象需要通过一个中间类来封装多个类中的行为,但又不想生成太多的子类2.2 中介者模式在MVC模式中的应用

比如说,在MVC框架中,控制器(Controller)就是模型(Model)和视图(View)之间的中介者:

Model(模型):代表一个存取对象的数据,有Dao、Bean等等View(视图):表示所看到的东西,比如网页、JSP等用于展示模型中的数据Controller(控制器):作用于模型和视图中间,控制数据流向模型对象,在数据变化时更新视图image-20220407153000058image-20220407153000058三、中介者模式实战3.1 ORM框架

我们知道在Java与数据库交互中JDBC可以完成对多种数据库操作,举一个利用JDBC查询的例子:

代码语言:javascript复制//1.加载MySQL驱动注入到DriverManager Class.forName("com.mysql.cj.jdbc.Driver"); //2.提供JDBC连接的URL、用户名和密码 String url = "jdbc:mysql://localhost:3306/test_db?"; String username = "root"; String password = "root"; //3.创建数据库的连接 Connection connection = DriverManager.getConnection(url, username, password); //4.创建statement实例 Statement statement = connection.createStatement(); //5.1执行SQL语句,得到ResultSet对象, String query = "select * from test"; //查询语句,也可以换成CRUD的其他语句 ResultSet resultSet = statement.executeQuery(query); while(resultSet.next()){ //5.2通过ResultSet读取数据后,将数据转换成JavaBean对象 } //6.关闭连接对象 connection.close();

在上面的步骤中,步骤1~4和6都可以封装重复执行,但是在第5步中,需要完成关系模型ResultSet到对象模型JavaBean的转换,而这一部分使用通用的方式封装这种复杂的转换是比较困难的,因此有ORM(Object Relational Mapping, 对象-关系映射)框架来解决对象转换关系模型的映射问题。同时也屏蔽了之前JDBC连接中的重复代码,只提供简单的API供开发人员进行使用。

image-20220407163737476image-202204071637374763.2 利用中介者模式模仿MyBatis核心功能

在本案例中我们通过模仿MyBatis 中核心ORM框架功能,来使用中介者模式。首先来看看ORM框架在数据库和应用交互中的位置:

image-20220407153504379image-20220407153504379

从图中可以看出,ORM框架位于数据库层和应用层中间,相当于两者之间的中介。在实际MyBatis 实现过程中,不仅用到了中介者模式,还有工厂模式和建造者模式。

在ORM框架实现的核心类中,包括加载配置文件、对XML进行解析、获取数据库session、操作数据库以及返回结果等步骤。在ORM内部的结构如下图所示(来自《重学Java设计模式》):

image-20220407165437935image-20220407165437935左上框内是对数据库的定义和处理,包括 T selectOne、 List selectList等等右上是对数据库配置的开启session的工厂处理类,工厂会操作DefaultSqlSession最后是核心类SqlSessionFactoryBuilder,它可以实现处理工厂、解析文件、拿session等操作

下面就来看看具体代码

实战代码创建对应数据库、JavaBean和Dao接口

创建数据库design-mediatro,数据表user和school

image-20220407171710282image-20220407171710282

创建与数据库相对应的JavaBean、Dao接口

代码语言:javascript复制/** * @description: 学校类 * @author: wjw * @date: 2022/4/7 */ public class School { private Long id; private String name; private String address; private Date createTime; private Date updateTime; //get set... } /** * @description: 用户类 * @author: wjw * @date: 2022/4/7 */ public class User { private Long id; private String name; private Integer age; private Date createTime; private Date updateTime; //get set... } /** * @description: SchoolDao接口 * @author: wjw * @date: 2022/4/7 */ public interface ISchoolDao { User querySchoolInfoById(Long treeId); } /** * @description: 用户Dao接口 * @author: wjw * @date: 2022/4/7 */ public interface IUserDao { User queryUserInfoById(Long id); }mapper相关配置文件

mybatis-config-datasource

代码语言:javascript复制

School_Mapper

代码语言:javascript复制 SELECT id, name, address, createTime, updateTime FROM school WHERE id = #{id}

User_Mapper

代码语言:javascript复制 SELECT id, name, age, createTime, updateTime FROM user where id = #{id} SELECT id, name, age, createTime, updateTime FROM user WHERE age = #{age} mediator中介者部分

SqlSession ,定义对数据库操作的查询接口,包括一个结果和多个查询结果,同时包括有参和无参的方法

代码语言:javascript复制/** * @description: 各种查询接口 * @author: wjw * @date: 2022/4/7 */ public interface SqlSession { T selectOne(String statement); T selectOne(String statement, Object parameter); List selectList(String statement); List selectList(String statement, Object parameter); void close(); }

SqlSession具体实现类DefaultSqlSession,包装jdbc层

代码语言:javascript复制/** * @description: SqlSession具体实现类 * @author: wjw * @date: 2022/4/7 */ public class DefaultSqlSession implements SqlSession{ private Connection connection; private Map mapperElement; public DefaultSqlSession(Connection connection, Map mapperElement) { this.connection = connection; this.mapperElement = mapperElement; } @Override public T selectOne(String statement) { try { XNode xNode = mapperElement.get(statement); PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql()); ResultSet resultSet = preparedStatement.executeQuery(); List objects = resultSet2Obj(resultSet, Class.forName(xNode.getResultType())); return objects.get(0); } catch (Exception e) { e.printStackTrace(); } return null; } private List resultSet2Obj(ResultSet resultSet, Class clazz) { ArrayList list = new ArrayList(); try { ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); while (resultSet.next()) { T obj = (T) clazz.newInstance(); for (int i = 1; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有