设计模式系列之组合模式及其在JDK和MyBatis源码中的运用详解

简介: 设计模式系列之组合模式及其在JDK和MyBatis源码中的运用详解

这篇文章主要介绍了组合模式及其在JDK和MyBatis源码中的运用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

组合模式及其在JDK源码中的运用 前言组合和聚合什么是组合模式示例透明组合模式透明组合模式的缺陷安全组合模式 组合模式角色组合模式在JDK源码中的体现组合模式应用场景享元模式优缺点总结

前言

本文主要会讲述组合模式的用法,并会结合在JDK和MyBatis源码中的运用来进一步理解组合模式。

在编码原则中,有一条是:多用组合,少用继承。当然这里的组合和我们今天要讲的组合模式并不等价,这里的组合其实就是一种聚合,那么聚合和组合有什么区别呢?

组合和聚合

人在一起叫团伙,心在一起叫团队。用这句话来诠释组合与聚合的区别是相对恰当的。

聚合就是说各个对象聚合在一起工作,但是我没有你也行,我照样可以正常运行。但是组合呢,关系就比较密切,组合中的各个对象之间组成了一个整体,缺少了某一个对象就不能正常运行或者说功能会有很大缺陷。
也就是说聚合对象不具备相同生命周期,而组合的对象具有相同的生命周期

举个例子:
比如说电脑和U盘就是聚合,而电脑显示器和主机就是组合。

什么是组合模式

组合模式(Composite Pattern)也称之为整体-部分(Part-Whole)模式。组合模式的核心是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得单个对象和组合对象的使用具有一致性。组合模式属于结构型模式。

组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,最顶层的节点称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点如下图所示:

图片.png

讲了这么多,感觉有点抽象,所以依然是老规矩:Talk is cheap,Show you the code。

示例

组合模式有两种写法,分别是透明模式和安全模式。下面我们就以高考的科目为例来看看组合模式是如何体现在代码中的

透明组合模式

1、首先建立一个顶层的抽象科目类,这个类中定义了三个通用操作方法,但是均默认不支持操作

package com.zwx.design.pattern.composite.transparency;
 
/**
 * 顶层抽象组件
 */
public abstract class GkAbstractCourse {
  public void addChild(GkAbstractCourse course){
    System.out.println("不支持添加操作");
  }
 
  public String getName() throws Exception {
    throw new Exception("不支持获取名称");
  }
 
  public void info() throws Exception{
    throw new Exception("不支持查询信息操作");
  }
}

PS:这个类中的公共方法之所以不定义为抽象方法的原因是因为假如定义为抽象方法,那么所有的子类都必须重写父类方法,这样体现不出差异性。而这种通过抛异常的方式,如果子类需要用到的功能就重写覆盖父类方法即可。

2、新建一个普通科目类继承通用科目抽象类,这个类作为叶子节点,没有重写addChild方法,也就是这个类属于叶子节点,不支持添加子节点:

package com.zwx.design.pattern.composite.transparency;
 
/**
 * 普通科目类(叶子节点)
 */
public class CommonCource extends GkAbstractCourse {
  private String name;//课程名称
  private String score;//课程分数
 
  public CommonCource(String name, String score) {
    this.name = name;
    this.score = score;
  }
 
  @Override
  public String getName(){
    return this.name;
  }
 
  @Override
  public void info() {
    System.out.println("课程:" + this.name + ",分数:" + score);
  }
}

3、建立一个具有层级的节点,三个方法都重写了,支持添加子节点,这个类里面为了方便打印的时候看出层级关系,所以我定义了一个层级属性。

package com.zwx.design.pattern.composite.transparency;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 树枝节点
 */
public class LevelCource extends GkAbstractCourse{
  private List<GkAbstractCourse> courseList = new ArrayList<>();
  private String name;
  private int level;
 
  public LevelCource(String name, int level) {
    this.name = name;
    this.level = level;
  }
 
  @Override
  public void addChild(GkAbstractCourse course) {
    courseList.add(course);
  }
 
  @Override
  public String getName(){
    return this.name;
  }
 
  @Override
  public void info() throws Exception {
    System.out.println("课程:" + this.name);
    for (GkAbstractCourse course : courseList){
      for (int i=0;i<level;i++){
        System.out.print(" ");
      }
      System.out.print(">");
      course.info();
    }
  }
}

4、建立一个测试类来测试一下:

package com.zwx.design.pattern.composite.transparency;
 
public class TestTransparency {
  public static void main(String[] args) throws Exception {
    GkAbstractCourse ywCourse = new CommonCource("语文","150");
    GkAbstractCourse sxCourse = new CommonCource("数学","150");
    GkAbstractCourse yyCourse = new CommonCource("英语","150");
 
    GkAbstractCourse wlCourse = new CommonCource("物理","110");
    GkAbstractCourse hxCourse = new CommonCource("化学","100");
    GkAbstractCourse swCourse = new CommonCource("生物","90");
 
    GkAbstractCourse lzCourse = new LevelCource("理综",2);
    lzCourse.addChild(wlCourse);
    lzCourse.addChild(hxCourse);
    lzCourse.addChild(swCourse);
 
    GkAbstractCourse gkCourse = new LevelCource("理科高考科目",1);
    gkCourse.addChild(ywCourse);
    gkCourse.addChild(sxCourse);
    gkCourse.addChild(yyCourse);
    gkCourse.addChild(lzCourse);
     
    gkCourse.info();
  }
}

输出结果:

课程:理科高考科目
      >课程:语文,分数:150
      >课程:数学,分数:150
      >课程:英语,分数:150
      >课程:理综
        >课程:物理,分数:110
        >课程:化学,分数:100
        >课程:生物,分数:90

这里如果用普通科目去调用add方法就会抛出异常,假如上面调用:

swCourse.addChild(ywCourse);

会输出

不支持添加操作

因为在普通科目类里面并没有重写addChild方法。

透明组合模式的缺陷

透明模式的特点就是将组合对象所有的公共方法都定义在了抽象组件内,这样做的好处是客户端无需分辨当前对象是属于树枝节点还是叶子节点,因为它们具备了完全一致的接口,不过缺点就是叶子节点得到到了一些不属于它的方法,比如上面的addChild方法,这违背了接口隔离性原则。

安全组合模式

安全组合模式只是规定了系统各个层次的最基础的一致性行为,而把组合(树节点)本身的方法(如树枝节点管理子类的addChild等方法)放到自身当中。

1、首先还是建立一个顶层的抽象根节点(这里面只定义了一个通用的抽象info方法):

package com.zwx.design.pattern.composite.safe;
 
package com.zwx.design.pattern.composite.safe;
 
/**
 * 顶层抽象组件
 */
public abstract class GkAbstractCourse {
  protected String name;
  protected String score;
 
  public GkAbstractCourse(String name, String score) {
    this.name = name;
    this.score = score;
  }
 
  public abstract void info();
}

2、建立一个叶子节点(这里只是重写了info方法,没有定义其他特有方法):

package com.zwx.design.pattern.composite.safe;
 
/**
 * 叶子节点
 */
public class CommonCource extends GkAbstractCourse {
 
  public CommonCource(String name,String score) {
    super(name,score);
  }
 
  @Override
  public void info() {
    System.out.println("课程:" + this.name + ",分数:" + this.score);
  }
}

3、定义一个树枝节点(这个类当中定义了一个树枝特有的方法addChild):

package com.zwx.design.pattern.composite.safe;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 树枝节点
 */
public class LevelCource extends GkAbstractCourse{
  private List<GkAbstractCourse> courseList = new ArrayList<>();
  private int level;
 
  public LevelCource(String name, String score,int level) {
    super(name,score);
    this.level = level;
  }
 
  public void addChild(GkAbstractCourse course) {
    courseList.add(course);
  }
 
  @Override
  public void info() {
    System.out.println("课程:" + this.name + ",分数:" + this.score);
    for (GkAbstractCourse course : courseList){
      for (int i=0;i<level;i++){
        System.out.print(" ");
      }
      System.out.print(">");
      course.info();
    }
  }
}

4、新建测试类来测试:

package com.zwx.design.pattern.composite.safe;
 
public class TestSafe {
  public static void main(String[] args) throws Exception {
    CommonCource ywCourse = new CommonCource("语文","150");
    CommonCource sxCourse = new CommonCource("数学","150");
    CommonCource yyCourse = new CommonCource("英语","150");
 
    CommonCource wlCourse = new CommonCource("物理","110");
    CommonCource hxCourse = new CommonCource("化学","100");
    CommonCource swCourse = new CommonCource("生物","90");
 
    LevelCource lzCourse = new LevelCource("理综","300",2);
    lzCourse.addChild(wlCourse);
    lzCourse.addChild(hxCourse);
    lzCourse.addChild(swCourse);
 
    LevelCource gkCourse = new LevelCource("理科高考","750",1);
    gkCourse.addChild(ywCourse);
    gkCourse.addChild(sxCourse);
    gkCourse.addChild(yyCourse);
 
    gkCourse.addChild(lzCourse);
    gkCourse.info();
  }
}

输出结果为:

     课程:理科高考,分数:750
      >课程:语文,分数:150
      >课程:数学,分数:150
      >课程:英语,分数:150
      >课程:理综,分数:300
        >课程:物理,分数:110
        >课程:化学,分数:100
        >课程:生物,分数:90

这里和透明方式不一样,叶子节点不具备addChild功能,所以无法调用,而上面的示例中时可以被调用,但是调用之后显示不支持,这就是这两种写法最大的区别。

组合模式角色

从上面示例中,可以看到组合模式包含了以下三个角色:

抽象根节点(Component):定义系统各层次对象的公有属性和方法,可以预先定义一些默认行为和属性。

树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。

叶子节点(Leaf):是系统遍历层次中的最小单位,下面没有子节点。

组合模式在JDK源码中的体现

1、HashMap

HashMap中有一个putAll方法,参数是一个Map,这就是一种组合模式的体现:

图片.png

另外还有ArrayList中的addAll方法也是一样。

2、MyBatis中有一个SqlNode接口,下面很多一级标签:

图片.png

然后一级标签下面又有二级标签(这就是组合模式的体现):

图片.png

组合模式应用场景

组合模式一般应用在有层级关系的场景,最经典的就是树形菜单,文件和文件夹的管理等

享元模式优缺点

优点:清楚的定义了分层次的复杂对象,让客户端可以忽略层次的差异,方便对整个层次进行动态控制。
缺点:其叶子和树枝的声明是实现类而不是接口,违反了依赖倒置原则,而且组合模式会使设计更加抽象不好理解。

总结

本文主要介绍了组合模式,并介绍了普通的聚合和组合之间的区别,并通过例子详细解释了组合模式中的透明写法和安全写法的区别,最后结合在JDK和MyBatis源码中的运用来进一步理解组合模式的运用。
请关注我,和我一起学习进步。

到此这篇关于设计模式系列之组合模式及其在JDK和MyBatis源码中的运用详解的文章就介绍到这了,更多相关组合模式在JDK和MyBatis源码中的运用内容请搜索"java开发全栈"以前的文章或继续浏览下面的相关文章希望大家以后多多支持"java开发全栈"!

相关文章
|
2月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
4月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 组合模式
js设计模式【详解】—— 组合模式
52 7
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
405 37
|
2月前
|
设计模式 Java
Java设计模式:组合模式的介绍及代码演示
组合模式是一种结构型设计模式,用于将多个对象组织成树形结构,并统一处理所有对象。例如,统计公司总人数时,可先统计各部门人数再求和。该模式包括一个通用接口、表示节点的类及其实现类。通过树形结构和节点的通用方法,组合模式使程序更易扩展和维护。
Java设计模式:组合模式的介绍及代码演示
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
42 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
125 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
2月前
|
设计模式 存储 缓存
JDK中都用了哪些设计模式?
JDK中都用了哪些设计模式?
49 7
|
2月前
|
设计模式 存储 安全
Java设计模式-组合模式(13)
Java设计模式-组合模式(13)
|
3月前
|
XML Java 数据库连接
mybatis源码研究、搭建mybatis源码运行的环境
这篇文章详细介绍了如何搭建MyBatis源码运行的环境,包括创建Maven项目、导入源码、添加代码、Debug运行研究源码,并提供了解决常见问题的方法和链接到搭建好的环境。
mybatis源码研究、搭建mybatis源码运行的环境
|
3月前
|
算法 安全 Java
深入JDK源码:揭开ConcurrentHashMap底层结构的神秘面纱
【8月更文挑战第24天】`ConcurrentHashMap`是Java并发编程中不可或缺的线程安全哈希表实现。它通过精巧的锁机制和无锁算法显著提升了并发性能。本文首先介绍了早期版本中使用的“段”结构,每个段是一个带有独立锁的小型哈希表,能够减少线程间竞争并支持动态扩容以应对高并发场景。随后探讨了JDK 8的重大改进:取消段的概念,采用更细粒度的锁控制,并引入`Node`等内部类以及CAS操作,有效解决了哈希冲突并实现了高性能的并发访问。这些设计使得`ConcurrentHashMap`成为构建高效多线程应用的强大工具。
53 2

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78