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

目录

一、什么是组合模式

二、组合模式的角色

三、组合模式的典型应用

四、组合模式在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.mzph.cn/pingmian/59143.shtml

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

相关文章

API网关 - JWT认证 ; 原理概述与具体实践样例

API网关主要提供的能力&#xff0c;就是协议转换&#xff0c;安全&#xff0c;限流等能力。 本文主要是分享 如何基于API网关实现 JWT 认证 。 包含了JWT认证的流程&#xff0c;原理&#xff0c;与具体的配置样例 API网关认证的重要性 在现代Web应用和微服务架构中&#x…

ArcGIS 地理信息系统 任意文件读取漏洞复现

0x01 产品简介 ArcGIS是由美国Esri公司研发的地理信息系统(GIS)软件,它整合了数据库、软件工程、人工智能、网络技术、云计算等主流的IT技术,旨在为用户提供一套完整的、开放的企业级GIS解决方案,它包含了一套带有用户界面组件的Windows桌面应用。可以实现从简单到复杂的…

一文了解Android SELinux

在Android系统中&#xff0c;SELinux&#xff08;Security-Enhanced Linux&#xff09;是一个增强的安全机制&#xff0c;用于对系统进行强制访问控制&#xff08;Mandatory Access Control&#xff0c;MAC&#xff09;。它限制了应用程序和进程的访问权限&#xff0c;提供了更…

如何看待AI技术的应用前景?

文章目录 如何看待AI技术的应用前景引言AI技术的现状1. AI的定义与分类2. 当前AI技术的应用领域 AI技术的应用前景1. 经济效益2. 社会影响3. 技术进步 AI技术应用面临的挑战1. 数据隐私与安全2. 可解释性与信任3. 技能短缺与就业影响 AI技术的未来发展方向1. 人工智能的伦理与法…

Java | Leetcode Java题解之第539题最小时间差

题目&#xff1a; 题解&#xff1a; class Solution {public int findMinDifference(List<String> timePoints) {int n timePoints.size();if (n > 1440) {return 0;}Collections.sort(timePoints);int ans Integer.MAX_VALUE;int t0Minutes getMinutes(timePoint…

讲讲 kafka 维护消费状态跟踪的方法?

大家好&#xff0c;我是锋哥。今天分享关于【讲讲 kafka 维护消费状态跟踪的方法&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 讲讲 kafka 维护消费状态跟踪的方法&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Kafka 中&#x…

多核架构的基本概念

目录 1.为什么使用多核 2.多核分类 2.1 同构和异构 2.2 SMP和AMP 3 小结 1.为什么使用多核 这个问题个人认为可以从两个方面来看&#xff1a; 性能问题 随着汽车ECU对集成化的要求越来越高&#xff0c;把多个ECU功能集中到一个多核MCU的需求也越来越明显。 以汽车制动…

GitHub | 发布到GitHub仓库并联文件夹的方式

推送到Github 推送步骤如果你只想更新单个文件&#xff0c;只需在第 4 步中指定该文件的路径即可。可能问题一 效果 推送步骤 更新 GitHub 仓库中的文件通常涉及以下步骤&#xff1a; 克隆仓库&#xff1a; 首先&#xff0c;你需要将 GitHub 上的仓库克隆到本地。使用 git …

【ArcGIS】绘制各省碳排放分布的中国地图

首先&#xff0c;准备好各省、自治区、直辖市及特别行政区&#xff08;包括九段线&#xff09;的shp文件&#xff1a; 通过百度网盘分享的文件&#xff1a;GS&#xff08;2022&#xff09;1873 链接&#xff1a;https://pan.baidu.com/s/1wq8-XM99LXG_P8q-jNgPJA 提取码&#…

【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0

目录 一、相关面试题 1. HTTP 与 HTTPS 有哪些区别&#xff1f; 2. HTTPS 的工作原理&#xff1f;&#xff08;https 是怎么建立连接的&#xff09; &#xff08;1&#xff09;ClientHello &#xff08;2&#xff09;SeverHello &#xff08;3&#xff09;客户端回应 &a…

FastAPI 请求体解析:基础概念与综合应用

FastAPI 请求体解析&#xff1a;基础概念与综合应用 本文深入探讨了 FastAPI 中的请求体概念&#xff0c;强调使用 Pydantic 模型来声明请求体数据结构。通过具体示例&#xff0c;展示了如何定义请求体、可选参数及默认值&#xff0c;提升数据验证和类型提示的便利性。文章还说…

Python并发编程库:Asyncio的异步编程实战

Python并发编程库&#xff1a;Asyncio的异步编程实战 在现代应用中&#xff0c;并发和高效的I/O处理是影响系统性能的关键因素之一。Python的asyncio库是专为异步编程设计的模块&#xff0c;提供了一种更加高效、易读的并发编程方式&#xff0c;适用于处理大量的I/O密集型任务…

Golang--数组、切片、映射

1、数组 1.1 数组类型 var 数组名 [数组大小]数据类型 package main import "fmt"func main(){//1、定义一个数组var arr1 [5]intarr1[0] 100arr1[1] 200fmt.Println(arr1) //[100 200 0 0 0] } 1.2 数组的初始化方式 package main import "fmt" func …

在VS中安装chatGPT

2、在VSCode中打开插件窗口 3、输入ChatGPT 4、这里有个ChatGPT中文版&#xff0c;就它了 5、安装 6、这时候侧边栏多了一个chatGPT分页图标&#xff0c;点击它 7、打个招呼 8、好像不行 9、看一下细节描述 10、根据要求按下按下快捷键 Ctrl Shift P 11、切换成国内模式 12、…

Linux下的Debugfs

debugfs 1. 简介 类似sysfs、procfs&#xff0c;debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件&#xff0c;procfs和进程相关的特性&#xff0c;debugfs的灵活度很大&#xff0c;可以根据需求对指定的变量进行导出并提供读写接口。debugfs又是一个Li…

Fooocus图像生成软件本地部署教程:在Windows上快速上手AI创作

文章目录 前言1. 本地部署Fooocus图像生成软件1.1 安装方式1.2 功能介绍 2. 公网远程访问Fooocus3. 固定Fooocus公网地址 前言 本篇文章将介绍如何在本地Windows11电脑部署开源AI生图软件Fooocus&#xff0c;并结合Cpolar内网穿透工具轻松实现公网环境远程访问与使用。 Foooc…

修改HarmonyOS鸿蒙图标和名字,打包后安装到真机,应用图标丢失变成透明,修改名字也不生效,还是默认的labeL解决方案教程

HarmonyOS鸿蒙打包hap 安装应用到桌面没有图标&#xff0c;用hdc安装到真机&#xff0c;打包后应用图标丢失变成透明&#xff0c;名字也还是默认的label的bug&#xff0c;以下是解决方案 以下是修改方案&#xff1a; 1、修改应用名字&#xff1a; 2、修改应用图标&#xff1a…

Python小游戏20——超级玛丽

首先&#xff0c;你需要确保你的Python环境中安装了pygame库。如果还没有安装&#xff0c;可以使用以下命令进行安装&#xff1a; bash pip install pygame 运行效果展示 代码展示 python import pygame import sys # 初始化pygame pygame.init() # 设置屏幕尺寸 screen_width …

从富文本窥探苹果的代码秘密

从富文本窥探苹果的代码秘密 背景 在我们的业务场景下&#xff0c;为突出诸如 “利益点”和“利率” 等特性以推动订单成交&#xff0c;引入了 “富文本” 这一概念。富文本具备丰富格式的文本展示与编辑功能。然而&#xff0c;恰是由于富文本具有 “多样式”“复杂排版” 等特…

openstack之guardian介绍与实例创建过程

运行特征 采集模块&#xff1a;扩展Ceilometer&#xff0c;采集存储网、业务网连通性、nova目录是否可读写&#xff1b; 收集模块&#xff1a;将采集到的数据存储到数据库中&#xff1b; 分析模块&#xff1a;根据采集的结果&#xff0c;分析各节点状态&#xff0c;并进行反向检…