【设计模式系列】组合模式(十二)

目录

一、什么是组合模式

二、组合模式的角色

三、组合模式的典型应用

四、组合模式在Mybatis SqlNode中的应用

4.1 XML映射文件案例

4.2 Java代码使用案例


一、什么是组合模式

组合模式(Composite Pattern)是一种结构型设计模式,其核心思想是将对象组合成树状结构,使得单个对象和对象的组合能够以相同的方式被处理。这种模式提供了一个将对象表示为部分-整体层次结构的方法,允许客户端对单个对象和组合对象的使用具有一致性。

二、组合模式的角色

  1. Component(抽象构件)

    • 作用:定义了对象结构的公共接口,包括业务方法和在需要时访问和管理其子构件的方法(如addremovegetChild)。这个接口可以是抽象类或接口。
    • 细节:Component作为组合中的对象的公共类或接口,使得叶子构件和组合构件可以被统一对待。
  2. Leaf(叶子构件)

    • 作用:表示对象结构中的叶节点,没有子构件。叶子构件实现了抽象构件定义的接口,但是其add或remove操作通常不做任何事情(可能是抛出异常或者简单返回)。
    • 细节:Leaf对象通常包含实现细节,因为它们不包含子构件,所以它们是实际执行业务逻辑的末端对象。
  3. Composite(组合构件)

    • 作用:表示对象结构中的复合节点,它可以包含子构件。Composite对象存储子构件集合,并实现在抽象构件中定义的方法来管理子构件。
    • 细节:Composite对象实现了添加和删除子构件的方法,并且通常会递归地调用其子构件的业务方法,以确保整个结构的一致性。

三、组合模式的典型应用

  1. 构建树形结构:任何需要表示部分-整体层次结构的场景,如组织架构、类目体系等。

  2. 创建复杂对象:在需要构建复杂对象,而这些对象由更简单的对象组成时,如构建一个由多个部件组成的汽车对象。

  3. 处理递归结构:当需要处理递归结构的数据时,如遍历、搜索、排序等操作。

  4. 实现插件架构:在需要构建一个可扩展的插件架构时,可以使用组合模式来表示插件的层次结构。

四、组合模式在Mybatis SqlNode中的应用

4.1 XML映射文件案例

  1. 动态SQL构建:MyBatis的动态SQL功能通过<if><choose><when><otherwise><trim><where><set><foreach>等标签,组合成非常灵活的SQL语句,提高开发人员的效率。

  2. SqlNode接口SqlNode接口是MyBatis中用于存储SQL的节点,它有一个apply抽象方法,用于将SQL节点应用到动态上下文中。

以下是SqlNode接口及其两个实现类MixedSqlNodeIfSqlNode的简单示例:

public interface SqlNode {boolean apply(DynamicContext context);
}public class MixedSqlNode implements SqlNode {private final List<SqlNode> contents;public MixedSqlNode(List<SqlNode> contents) {this.contents = contents;}@Overridepublic boolean apply(DynamicContext context) {contents.forEach(node -> node.apply(context));return true;}
}public class IfSqlNode implements SqlNode {private ExpressionEvaluator evaluator;private String test;private SqlNode contents;public IfSqlNode(SqlNode contents, String test) {this.test = test;this.contents = contents;this.evaluator = new ExpressionEvaluator();}@Overridepublic boolean apply(DynamicContext context) {if (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;}
}

使用案例

假设我们有一个用户表(users),包含字段idnameemailstatus。我们需要根据不同的条件动态生成查询SQL。

<select id="selectUsers" resultType="User">SELECT * FROM users<where><if test="name != null">AND name = #{name}</if><if test="status != null">AND status = #{status}</if></where><if test="emails != null and emails.size > 0">AND email IN<foreach item="email" collection="emails" open="(" separator="," close=")">#{email}</foreach></if>
</select>

在这个例子中,<where>标签内部包含了两个<if>标签,这两个<if>标签对应的SqlNode会被MixedSqlNode组合在一起进行处理。如果namestatus不为空,相应的条件会被添加到SQL中。如果emails列表不为空,<foreach>标签会生成一个IN条件子句,其中每个邮箱地址都会被包含在列表中。

通过这种方式,MyBatis能够根据传入的参数动态地构建SQL语句,使得SQL语句的构建更加灵活和强大。这种模式的应用提高了MyBatis动态SQL的灵活性和可扩展性。

4.2 Java代码使用案例

1. 定义SqlNode接口和实现类

首先,定义SqlNode接口和一些实现类,包括TextSqlNodeIfSqlNodeForEachSqlNode

public interface SqlNode {boolean apply(DynamicContext context);
}public class TextSqlNode implements SqlNode {private String text;public TextSqlNode(String text) {this.text = text;}@Overridepublic boolean apply(DynamicContext context) {context.appendText(text);return true;}
}public class IfSqlNode implements SqlNode {private String condition;private SqlNode ifTrue;public IfSqlNode(String condition, SqlNode ifTrue) {this.condition = condition;this.ifTrue = ifTrue;}@Overridepublic boolean apply(DynamicContext context) {if (Boolean.parseBoolean(context.getBindings().getOrDefault(condition, "false").toString())) {return ifTrue.apply(context);}return false;}
}public class ForEachSqlNode implements SqlNode {private String collection;private String item;private String open;private String close;private String separator;private SqlNode contents;public ForEachSqlNode(String collection, String item, String open, String close, String separator, SqlNode contents) {this.collection = collection;this.item = item;this.open = open;this.close = close;this.separator = separator;this.contents = contents;}@Overridepublic boolean apply(DynamicContext context) {List<String> emails = (List<String>) context.getBindings().get(collection);if (emails != null && !emails.isEmpty()) {context.appendText(open);for (int i = 0; i < emails.size(); i++) {context.getBindings().put(item, emails.get(i));contents.apply(context);if (i < emails.size() - 1) {context.appendText(separator);}}context.appendText(close);}return true;}
}

2. 创建DynamicContext类

DynamicContext类用于存储和传递动态SQL生成过程中的上下文信息:

import java.util.HashMap;
import java.util.Map;public class DynamicContext {private StringBuilder sql = new StringBuilder();private Map<String, Object> bindings = new HashMap<>();public void appendText(String text) {sql.append(text);}public String getSql() {return sql.toString();}public Map<String, Object> getBindings() {return bindings;}public void setBindings(Map<String, Object> bindings) {this.bindings = bindings;}
}

3. 使用SqlNode构建和执行动态SQL

在Java代码中使用SqlNode构建和执行动态SQL:

public class Main {public static void main(String[] args) {DynamicContext context = new DynamicContext();Map<String, Object> params = new HashMap<>();params.put("name", "John Doe");params.put("status", "ACTIVE");params.put("emails", List.of("john.doe@example.com", "jane.doe@example.com"));context.setBindings(params);SqlNode rootNode = new TextSqlNode("SELECT * FROM users WHERE ");rootNode.apply(context);new IfSqlNode("name != null",new TextSqlNode("AND name = #{name}")).apply(context);new IfSqlNode("status != null",new TextSqlNode("AND status = #{status}")).apply(context);new IfSqlNode("emails != null && !emails.isEmpty()",new ForEachSqlNode("emails", "email", "(", ")", ",",new TextSqlNode("AND email = #{email}"))).apply(context);System.out.println("Generated SQL: " + context.getSql());}
}

在这个示例中,DynamicContext类用于存储和传递动态SQL生成过程中的上下文信息。Main类展示了如何使用SqlNode构建和执行动态SQL。IfSqlNodeTextSqlNode用于条件判断和添加文本,而ForEachSqlNode用于处理集合类型的参数,模拟MyBatis中的<foreach>标签。

这个示例展示了如何在Java代码中模拟MyBatis的动态SQL行为,包括使用ForEachSqlNode来处理集合类型的参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/464328.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg 4.3 音视频-多路H265监控录放C++开发十二:在屏幕上显示多路视频播放,可以有不同的分辨率,格式和帧率。

上图是在安防领域的要求&#xff0c;一般都是一个屏幕上有显示多个摄像头捕捉到的画面&#xff0c;这一节&#xff0c;我们是从文件中读取多个文件&#xff0c;显示在屏幕上。

Linux下Java的多种方式安装

Linux下Java的多种方式安装 博客&#xff1a; www.lstar.icu 开源地址 Gitee 地址&#xff1a; https://gitee.com/lxwise/iris-blog_parent Github 地址&#xff1a; https://github.com/lxwise/iris-blog_parent 序言 Java是一门面向对象的编程语言&#xff0c;不仅吸收了…

鸿蒙进阶-AlphabetIndexer组件

大家好&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习AlphabetIndexer组件&#xff0c;喜欢就点点关注吧&#xff01; 通过 AlphabetIndexer 组件可以与容器组件结合&#xff0c;实现导航联动&#xff0c;以及快速定位的效果 核心用法 AlphabetIndexer不是容器组件…

WordPress之generatepress主题安装

1.打开主题列表 2.如果没有自己需要主题点击安装新主题 点击安装并启用 3.不喜欢的 主题可以点击主题进去删除 4.主题自定义编辑 打开自定义&#xff0c;可以修改布局&#xff0c;颜色&#xff0c;排版等等

我们来学mysql -- 同时使用 AND 和 OR 查询错误(填坑篇)

AND 和 OR 一同使用问题 现象分析处理扩展 现象 业务上在“锁定”当前零件所在出口国的所有零件时&#xff0c;出现其他国家零件 问题定位 分析 or 切断了操作符之间的连续性&#xff0c;从union角度分析 where k1 Td621 and k1 Vda96 or k3 P00009等同 select * fr…

CloudCompare——基于连通性的点云分类【2024最新版】

目录 1.实现原理2.找到连通性分类功能3.设置计算参数4.分类结果5.完整操作流程 1.实现原理 见&#xff1a;http://en.wikipedia.org/wiki/Connected-component_labeling。 2.找到连通性分类功能 “Tools > Segmentation > Label Connected Comp”菜单进行打开 3.设置…

Axure大屏可视化模板:赋能各行各业的数据展示与管理

如何高效、直观地展示和分析数据&#xff0c;成为企业和机构面临的重要挑战。Axure大屏可视化模板作为一种先进的数据展示工具&#xff0c;凭借其强大的交互性和直观性&#xff0c;在多个领域内得到了广泛应用。从农业生产的智能化管理到城市发展的精细化管理&#xff0c;再到企…

模型 海勒姆法则(用户依赖你未承诺的API功能)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。用户总会以你意想不到的方式使用你的产品。 1 海勒姆法则的应用 1.1 社交网络平台API的变更 一个流行的社交网络平台“Socialville”拥有数百万用户&#xff0c;它提供了一个API&#xff0c;允许开发…

Rust 力扣 - 1423. 可获得的最大点数

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 题目所求结果存在下述等式 可获得的最大点数 所有卡牌的点数之和 - 长度为&#xff08;卡牌数量 - k&#xff09;的窗口的点数之和的最小值 我们遍历长度为&#xff08;卡牌数量 - k&#xff09;的窗口&#…

如何对LabVIEW软件进行性能评估?

对LabVIEW软件进行性能评估&#xff0c;可以从以下几个方面着手&#xff0c;通过定量与定性分析&#xff0c;全面了解软件在实际应用中的表现。这些评估方法适用于确保LabVIEW程序的运行效率、稳定性和可维护性。 一、响应时间和执行效率 时间戳测量&#xff1a;使用LabVIEW的时…

「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现

本篇将带你实现一个滑动选择器应用&#xff0c;用户可以通过滑动条选择不同的数值&#xff0c;并实时查看选定的值和提示。这是一个学习如何使用 Slider 组件、状态管理和动态文本更新的良好实践。 关键词 UI互动应用Slider 组件状态管理动态数值更新用户交互 一、功能说明 在…

docker pull 拉取镜像失败,使用Docker离线包

1、登录并注册Github&#xff0c;然后在Github中搜索并打开“wukongdaily/DockerTarBuilder” 项目&#xff0c;在该项目主页点击“Fork”。 然后点 “Create Fork”&#xff0c;将项目创建到自己的Github主页。 2、接着在自己创建过来的这个项目中点击“Actions” 3、然后…

使用JdbcTemplate 进行数据库的增、删、改、查

一、概述 1、为什么选择 Spring Boot ? Spring Boot 是目前 Java 社区最流行、最有影响力的技术之一&#xff0c;也是下一代企业级应用开发的首选技术。Spring Boot 由 Spring 衍生而来&#xff0c;继承了其所有的有点&#xff0c;为开发者带来了巨大的便利。 “We use a lo…

EHOME视频平台EasyCVR萤石设备视频接入平台视频诊断技术可以识别哪些视频质量问题?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。萤石设备视频接入平台EasyCVR不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能&#xff0c;还支持多种主流标准协议&#xff0c;如GB28181、GB35114、RTSP/Onvif…

这款Chrome 插件,帮助我们复制网页上不能复制的内容

前言 最近在上网查找博客时&#xff0c;经常遇到想要复制网页上的内容&#xff0c;但是&#xff0c;一点击复制&#xff0c;就会弹出来各种各样的弹框&#xff0c;导致复制不能继续&#xff0c;非常麻烦。这时&#xff0c;我想到了一个办法&#xff0c;那就是下载安装一个chro…

数字后端零基础入门系列 | Innovus零基础LAB学习Day8

###LAB15 Detail Routing for Signal Integrity, Timing, Power and Design for Yield 这个章节虽然标题有点长&#xff0c;但不要被它吓到&#xff0c;其实这个章节就是Innovus工具的绕线Routing。只不过这个阶段做Route不是仅仅是把所有的逻辑连接&#xff0c;用实际的金属层…

ISUP协议视频平台EasyCVR视频融合平台接入各类摄像机的方法

安防视频监控ISUP协议视频平台EasyCVR兼容性强、支持灵活拓展&#xff0c;平台可提供视频远程监控、录像、存储与回放、视频转码、视频快照、告警、云台控制、语音对讲、平台级联等视频能力。 想要将摄像机顺利接入EasyCVR平台&#xff0c;实现视频监控的集中管理和分发&#x…

QEMU学习之路(4)— Xilinx开源项目systemctlm-cosim-demo安装与使用

QEMU学习之路&#xff08;4&#xff09;— Xilinx开源项目systemctlm-cosim-demo安装与使用 一、前言 项目说明&#xff1a;https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/862421112/Co-simulation 操作系统&#xff1a;Ubuntu 20.04.6 LTS gcc版本&#xff1a;9.4…

【解决办法】无法使用右键“通过VSCode打开文件夹”

个人博客&#xff1a;苏三有春的博客 前言 作者的编程环境为VScode&#xff0c;工作时常使用VScode打开整个工程文件夹。如果先打开VScode再从VScode中选择文件夹打开效率太慢&#xff0c;作者一般使用的方式是右键文件夹&#xff0c;直接选择"通过code打开文件夹"…

Java环境下配置环境(jar包)并连接mysql数据库

目录 jar包下载 配置 简单连接数据库 一、注册驱动&#xff08;jdk6以后会自动注册&#xff09; 二、连接对应的数据库 以前学习数据库就只是操作数据库&#xff0c;根本不知道该怎么和软件交互&#xff0c;将存储的数据读到软件中去&#xff0c;最近学习了Java连接数据库…