✨这里是第七人格的博客✨小七,欢迎您的到来~✨
🍅系列专栏:设计模式🍅
✈️本篇内容:组合模式✈️
🍱本篇收录完整代码地址:gitee.com/diqirenge/d...🍱
楔子
小七最近工作可以说是忙到飞起,本来想着今天休息一下就不再更新了。但是!但是!但是!
今天下午居然被群友推荐鼓励了o( ̄▽ ̄)ブ,那必须得再干它一篇!
ps:有些朋友觉得设计模式太简单了,希望小七聊聊JUC和Spring源码。小七只想说不要方(●ˇ∀ˇ●),等设计模式这个专栏写完了,就开始更新JUC相关知识。
大纲都已经有了,可以浏览小七的github-page尝尝鲜 li-zong-yang.github.io/#/guide_ind...
需求背景
2022年小七研究过一段时间的接口编排,当时还给liteFlow提过一个Issues
Issues中举例的业务场景就很适合使用组合模式。
我们再将这个需求简单描述一下:
1、我们有2种检验注册的手段 a.手机号 b身份证
2、这两种校验手段在不同的业务场景下,有不同的组合,可以都参与校验,也可以只有一个参与校验。
分析设计
为了让我们的校验功能,能够进⾏⾃由组合对外提供服务。我们可以把这两种校验手段想象成两片叶子,他们可以自由组合成一棵完整的树。
首先我们抽象出组件接口ComponentChecker,让两个具体的校验类都实现它;
然后我们定义组合节点Composite,可以先理解成图中的root,它里面要包含子节点,所以我们得有一个list的属性
java
/**
* 可以存放子节点
*/
private List<ComponentChecker> children;
UML图
根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码
模块名称
composite
模块地址
模块描述
组合模式代码示例
代码实现
1、定义组件接口
java
/**
* 定义组件接口
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/11/30
*/
public interface ComponentChecker {
/**
* 校验
*/
void check();
}
具体实现子类-身份证校验器
java
/**
* 子节点 - 身份证校验器
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/11/30
*/
class IdCardChecker implements ComponentChecker {
private String number;
public IdCardChecker(String number) {
this.number = number;
}
@Override
public void check() {
System.out.println("校验身份证[" + number + "]被执行了...");
}
@Override
public String toString() {
return "IdCard{" +
"number='" + number + '\'' +
'}';
}
}
具体实现子类-电话校验器
java
/**
* 子节点 - 电话校验器
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/11/30
*/
class PhoneChecker implements ComponentChecker {
private String number;
public PhoneChecker(String number) {
this.number = number;
}
@Override
public void check() {
System.out.println("校验电话号码[" + number + "]被执行了...");
}
@Override
public String toString() {
return "Phone{" +
"number='" + number + '\'' +
'}';
}
}
2、定义组合节点
关键点是要将组件接口的集合作为属性放到类中
java
/**
* 定义组合节点
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/11/30
*/
class Composite implements ComponentChecker {
private String name;
/**
* 可以存放子节点
*/
private List<ComponentChecker> children;
public Composite(String name) {
this.name = name;
this.children = new ArrayList<>();
}
/**
* 添加子节点
*
* @param child 添加的节点
*/
public void addChild(ComponentChecker child) {
children.add(child);
}
/**
* 移除子节点
*
* @param child 删除的节点
*/
public void removeChild(ComponentChecker child) {
children.remove(child);
}
@Override
public void check() {
System.out.println("组合节点[" + name + "]准备开始执行\n叶子节点数据为:" + children.toString() + "\n");
for (ComponentChecker child : children) {
child.check();
}
}
@Override
public String toString() {
return "Composite{" +
"name='" + name + '\'' +
", children=" + children +
'}';
}
}
3、编写测试类
java
/**
* 测试组合模式
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/11/29
*/
public class CompositeTest {
@Test
public void testBridge() {
// 创建根节点,他是一个组合节点
Composite root = new Composite("根节点");
// 创建叶子节点1
IdCardChecker leaf1 = new IdCardChecker("500383*********");
root.addChild(leaf1);
// 创建叶子节点2
PhoneChecker leaf2 = new PhoneChecker("186*********");
root.addChild(leaf2);
// 执行操作
root.check();
}
}
5、测试结果
组合节点[根节点]准备开始执行
叶子节点数据为:[IdCard{number='500383 * * * * * * * * * '}, Phone{number='186 * * * * * * * * *'}]
校验身份证[500383 * * * * * * * * * *]被执行了...
校验电话号码[186* * * * * * * * * * * *]被执行了...
实现要点
-
抽象组件(Component):定义创建对象的接口,允许客户端独立地获取组件对象。
文中示例为:ComponentChecker
-
叶子节点(Leaf):继承/实现自抽象组件,表示叶子节点对象。
文中示例为:IdCardChecker和PhoneChecker
-
容器节点(Composite):继承自抽象组件,表示容器节点对象,包含子组件列表。
文中示例为:Composite;子组件列表为:private List children。
总结
组合模式是一种结构型设计模式,它将对象组织成树形结构,使得客户端可以以统一的方式处理单个对象和组合对象。