设计模式-组合模式

第一话:初代营销系统

技术背景
营销系统初期,技术负责人小易考虑到初期仅需支持两种渠道,采用直接耦合方式可快速上线

邮件活动
 

typescript

代码解读

复制代码

@Getter @Setter public class EmailCampaign {     private String name;     public EmailCampaign(String name) {         this.name = name;     }     public void execute() {         System.out.println("执行电子邮件活动: " + name);     } }

社交媒体活动
 

typescript

代码解读

复制代码

@Getter @Setter public class SocialMediaCampaign {     private String name;     public SocialMediaCampaign(String name) {         this.name = name;     }     public void execute() {         System.out.println("执行社交媒体活动: " + name);     } }

组合活动
 

csharp

代码解读

复制代码

public class BundleCampaign {     private EmailCampaign emailCampaign;     private SocialMediaCampaign socialMediaCampaign;     public BundleCampaign(EmailCampaign emailCampaign,SocialMediaCampaign socialMediaCampaign){         this.emailCampaign = emailCampaign;         this.socialMediaCampaign = socialMediaCampaign;     }     public void execute(){         emailCampaign.execute();         socialMediaCampaign.execute();         System.out.println("执行一系列活动: " + emailCampaign.getName() + " + " + socialMediaCampaign.getName());     } }

架构示意图
 

css

代码解读

复制代码

A[营销系统] A --> B[邮件活动] A --> C[社交活动] A --> D[硬编码组合]

埋下隐患

  • 新增活动类型需修改BundleCampaign类
  • 组合深度限制为固定两层
第二话:需求突袭

技术背景: 市场总监提出P0级需求:支持三级组合营销(主活动=短信+子组合(邮件+社交)),要求不影响线上运行。

临时方案:采用硬编码支持新类型,并新建一个短信活动。

短信活动
 

typescript

代码解读

复制代码

@Getter @Setter public class SMSCampaign {     private String name;     public SMSCampaign(String name) {         this.name = name;     }     public void execute() {         System.out.println("执行短信活动: " + name);     } }

硬编码组合类
 

typescript

代码解读

复制代码

public class BundleCampaign {     List<Object> campaigns = new ArrayList<>();     public void addCampaign(Object campaign) {         campaigns.add(campaign);     }     public void execute() {         for (Object obj : campaigns) {             if (obj instanceof EmailCampaign) {                 ((EmailCampaign) obj).execute();             }             else if (obj instanceof SocialMediaCampaign) {                 ((SocialMediaCampaign) obj).execute();             }             else if (obj instanceof SMSCampaign) {                 ((SMSCampaign) obj).execute();             }             else {                 return;             }         }     } }

方案缺陷

  • 当需要新增第四种活动时,不得不在 BundleCampaign 中添加更多 if-else
  • 每次新增活动,都需要修改核心逻辑,严重影响到测试的完整性
  • 判断中需要类型强制转换,嵌套组合支持不完善
第三话:设计模式重构

技术背景: 技术负责人小易考虑到若不对当前营销系统进行重构,很有可能在未来的某天出现重大系统故障问题,决定使用组合模式进行重构。

设计模式解析

核心思想:将对象组织成树形结构,统一处理单个对象和组合对象。
主要角色

  1. Component(抽象类):定义统一接口(如 execute()
  2. Leaf(叶子节点):基础活动(邮件、社交)
  3. Composite(组合节点):可包含其他 Component 的组合活动(BundleCampaign)
重构:应用组合模式
1. 定义抽象组件
 

typescript

代码解读

复制代码

@Getter @Setter public abstract class Campaign {     protected String name;     public Campaign(String name) {         this.name = name;     }     /**      * 定义活动执行抽象方法      */     public abstract void execute();     public void add(Campaign campaign) {         throw new UnsupportedOperationException("不支持组合活动");     } }

2. 叶子节点:基础活动
 

java

代码解读

复制代码

public class EmailCampaign extends Campaign {     public EmailCampaign(String name) {         super(name);     }     @Override     public void execute() {         System.out.println("执行电子邮件活动: " + name);     } } public class SMSCampaign extends Campaign {     public SMSCampaign(String name) {         super(name);     }     @Override     public void execute() {         System.out.println("执行短信活动: " + name);     } } public class SocialMediaCampaign extends Campaign {     public SocialMediaCampaign(String name) {         super(name);     }     @Override     public void execute() {         System.out.println("执行社交媒体活动: " + name);     } }

3. 组合节点:可嵌套的组合活动
 

typescript

代码解读

复制代码

public class BundleCampaign extends Campaign {     private List<Campaign> campaigns = new ArrayList<>();     public BundleCampaign(String name) {         super(name);     }     @Override     public void execute() {         System.out.println(name + " 开启!");         for (Campaign c : campaigns) {             c.execute();         }     }     @Override     public void add(Campaign campaign) {         campaigns.add(campaign);     } }

测试代码
 

ini

代码解读

复制代码

public class CompositeTest {     @Test     public void testCampaign() {         Campaign emailCampaign = new EmailCampaign("双十一折扣");         Campaign socialMediaCampaign = new SocialMediaCampaign("微博热搜");         Campaign bundleCampaign = new BundleCampaign("主活动");         bundleCampaign.add(emailCampaign);         bundleCampaign.add(socialMediaCampaign);         Campaign childBundle = new BundleCampaign("子活动");         childBundle.add(new SMSCampaign("追加优惠"));         bundleCampaign.add(childBundle);         bundleCampaign.execute();     } }

输出

 

makefile

代码解读

复制代码

主活动开启! 执行电子邮件活动: 双十一折扣 执行社交媒体活动: 微博热搜 子活动开启! 执行短信活动: 追加优惠

重构后效果
系统改进点
  1. 新增类型无需修改已有代码(符合开闭原则)
  2. 客户端无需区分叶子/组合节点(统一接口)
  3. 支持无限层级嵌套(灵活组合)
复杂度对比
维度重构前重构后
新增活动类型修改核心类新增叶子类即可
组合嵌套深度固定2层无限递归
类型安全检查运行时判断编译时保障
扩展成本O(n)线性增长O(1)恒定

长话短说

核心思想与使用指南

核心思想:
  • 统一性:客户端无需区分叶子节点和组合节点
  • 递归组合:通过树形结构实现无限嵌套
实施路线图
  1. 识别树形结构:找出系统中的层次关系
  2. 抽象组件接口:定义通用操作方法
  3. 区分叶子节点:实现不可再分的元素
  4. 构建复合节点:实现可嵌套的容器
  5. 实现递归逻辑:在复合节点中遍历子元素
  6. 添加类型约束(可选):通过安全模式限制操作
代码步骤
  1. 定义抽象类/接口,声明通用方法(如 execute())。
  2. 创建叶子类,实现基础功能。
  3. 创建组合类,管理子组件集合,并实现递归调用。
  4. 客户端通过抽象类型操作所有对象。

最佳实践场景

  1. 文件系统:文件与文件夹的统一管理
  2. 组织架构:部门与员工的层级关系
  3. UI组件:窗口与控件的嵌套组合
  4. 语法树:程序结构的抽象表示

关键决策点

何时选择组合模式?
  • 需要表示对象的部分-整体层次结构
  • 希望客户端忽略组合与单个对象的不同
  • 需要递归组合的结构化数据
何时避免使用?
  • 系统不存在明显的层次结构
  • 组合操作需要完全不同的接口
  • 性能敏感的叶子节点操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值