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

news2024/12/22 23:04:35

目录

一、什么是组合模式

二、组合模式的角色

三、组合模式的典型应用

四、组合模式在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;
    }

    @Override
    public 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();
    }

    @Override
    public 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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.coloradmin.cn/o/2231800.html

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

相关文章

Ghidra无头模式(自动化批处理执行重复性任务)

Ghidra无头模式&#xff08;自动化批处理执行重复性任务&#xff09; 与Ghidra GUI探索单个项目中的单个文件不同&#xff0c;Ghidra headless analyzer&#xff08;Ghidra无头分析器&#xff09;更加适合批处理和用脚本控制Ghidra。 &#xff08;一&#xff09;启动analyzeHea…

【大众点评】店铺评论 加密参数生成逆向分析

点击好评 https://www.dianping.com/ajax/json/shopDynamic/allReview 分析参数_token 直接搜_token 共17个&#xff0c;优先看和请求相关的 给第一个_token打上断点&#xff0c;然后切换评论&#xff0c;就直接断住了 n h(i, e.sendData) _token: n 现在给它打上断点&am…

Fsm3

采用读热码编写方式&#xff1a; module top_module(input clk,input in,input areset,output out); ////reg [3:0]A 4d0001;// reg [3:0]B 4d0010;//reg [3:0]C 4d0100;// reg [3:0]D 4d1000; //1、首先用读热码定义四个状态变量parameter A 4d0001 ,B 4d0010, C 4d01…

在腾讯云服务器上部署MaxKB项目(基于LLM大语言模型的知识库问答系统)

前言 一&#xff0c; MaxKB介绍 MaxKB是基于LLM大语言模型的知识库问答系统&#xff0c;旨在成为企业的最强大脑。它支持开箱即用&#xff0c;无缝嵌入到第三方业务系统&#xff0c;并提供多模型支持&#xff0c;包括主流大模型和本地私有大模型&#xff0c;为用户提供智能问…

【大众点评】加密参数生成逆向分析

点击好评 https://www.dianping.com/ajax/json/shopDynamic/allReview 分析参数_token 直接搜_token 共17个&#xff0c;优先看和请求相关的 给第一个_token打上断点&#xff0c;然后切换评论&#xff0c;就直接断住了 n h(i, e.sendData) _token: n 现在给它打上断点&am…

【Python+Pycharm】2024-Python安装配置教程

【PythonPycharm】2024-Python安装配置教程 一、下载装 Python 1、进入Python官网首页&#xff0c;下载最新的Python版本 Download Python | Python.org 选择对应版本下载 安装 测试安装情况 python如果安装失败 在系统环境变量添加安装路径 where pythonwin7安装路径添加…

Python中如何计算整商:详解整除运算及其应用场景

目录 一、整除运算的基本概念 1. 语法 2. 工作原理 二、整除运算的详细解析 1. 整数之间的整除 2. 浮点数之间的整除 3. 整数与浮点数之间的整除 三、整除运算的应用场景 1. 数据处理中的取整操作 2. 循环中的步进控制 3. 分页显示数据 4. 时间计算中的取整 四、整…

sql注入——靶场Less1

?id1 ?id99union select 1,2,3-- 查看占位 ?id1 order by 3-- 尝试出表有几列 ?id1 order by 4-- 说明只有三列 ?id99 union select 1,database(),3-- 查询当前使用的数据库的名称 ?id99 union select 1,group_concat(table_name),3 from information_schema.tables …

教你将华为手机投屏到macOS系统的电脑,协同办公不用愁!

这个信息爆炸的时代&#xff0c;工作效率成为了衡量个人能力的一个重要指标。很多人都了解过华为手机的协同办公能力&#xff0c;华为电脑也可以让多台华为手机同时显示在一个电脑屏幕里。 如果电脑不是华为的&#xff0c;电脑系统换成macOS&#xff0c;还能达到将多台华为手机…

【IC每日一题--单bitCDC跨时钟和同步FIFO】

IC Daily QA--CDC跨时钟和同步FIFO 1 八股题&#xff1a;CDC跨时钟数据传输问题--单bit跨时钟1.1 从慢时钟到快时钟--->直接打两拍即可&#xff1b;1.2 快时钟到慢时钟1.2.1 脉冲信号展宽边沿检测1.2.2 慢到快时钟--握手边沿 2 手撕题&#xff1a;同步FIFO代码&#xff1b;1…

零基础玩转IPC之——如何实现远程实时查看监控视频(P2P)

P2P是peer-to-peer的简称&#xff0c;又称为点对点技术&#xff0c;是没有中心服务器、依靠用户群节点进行信息交换的对等式网络。区别于传统的C/S中央服务器结构&#xff0c;P2P网络中每一个用户节点即是客户端又是服务端&#xff0c;能同时作为服务器给其他节点提供服务。 优…

ubuntu20安装opencv3.2记录

系统环境 ubuntu20安装了ros-noetic&#xff0c;所以系统默认装了opencv4.2.0&#xff0c;但是跑fastlivo推荐的是opencv3.2.0&#xff0c;而且海康相机别人写的ros驱动&#xff08;海康相机ros驱动&#xff09;也是需要opencv3.2.0&#xff0c;最终还是选择安装多版本的openc…

Ecosmos携手第二十六届高交会,开启元宇宙展会新纪元

2024年11月14日至16日&#xff0c;第二十六届中国国际高新技术成果交易会&#xff08;简称“高交会”&#xff09;将在深圳国际会展中心盛大举行。 本届高交会以“科技引领发展 产业融合聚变”为主题&#xff0c;展览面积达40万平方米&#xff0c;将设置22个专业展&#xff0c;…

奇瑞汽车:降阶模型在新能源汽车热管理仿真上的应用

随着新能源汽车的发展&#xff0c;对仿真技术的要求也越来越高。那么奇瑞汽车利用降阶模型在新能源汽车热管理仿真上做了哪些应用呢&#xff1f;本次内容主要从四个方面展开介绍&#xff1a; 1、 奇瑞汽车简介&#xff1b; 2、 热管理降阶模型开发的背景&#xff1b; 3、 高低…

【NLP-06】词形还原(Lemmatization)深度解析与实践

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

卖三蹦子的wordpress模板

Tricycle三奔子wordpress模板 卖三轮的跨境电商B2B产品展示型网站wordpress模板&#xff0c;助力二大爷的三奔子卖向全球&#xff0c;让在中国遍地热销的三蹦子在海外也大卖. https://www.jianzhanpress.com/?p8178

Java | Leetcode题解之第535题TinyURL的加密与解密

题目&#xff1a; 题解&#xff1a; public class Codec {private Map<Integer, String> dataBase new HashMap<Integer, String>();private Random random new Random();public String encode(String longUrl) {int key;while (true) {key random.nextInt();i…

NFTScan Site:以蓝标认证与高级项目管理功能赋能 NFT 项目

自 NFTScan Site 上线以来&#xff0c;它迅速成为 NFT 市场中的一支重要力量&#xff0c;凭借对各类 NFT 集合、市场以及 NFTfi 项目的认证获得了广泛认可。这个平台帮助许多项目提升了曝光度和可见性&#xff0c;为它们在竞争激烈的 NFT 市场中创造了更大的成功机会。 在最新更…

保研考研机试攻略:python笔记(2)

&#x1f428;&#x1f428;&#x1f428;宝子们好呀&#xff0c;今天我们继续来学习N诺提供的python笔记&#xff0c;fighting&#xff01;( •̀ ω •́ )✧ 对这个系列感兴趣的宝子欢迎关注保研考研机试攻略专栏哦 ~ 目录 &#x1f428;&#x1f428;&#x1f428;4进制转…

【动手学电机驱动】 STM32-FOC(2)STM32 导入和创建项目

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…