设计模式之组合模式
顾名思义,组合模式允许以相同的方式处理单个对象和对象的组合体。
也就是说这个组合类可以处理单个的对象,也可以处理对象的集合。
单节点组合
如上图所示,定义了一个工厂,产生消息对外的一个类,用于外部调用。
定义一个抽象类(SenderService),用于规范一些操作。
SmsService这个类才是应用了组合的类,
这里面最重要的是这个List , 自己添加自己?
/**
* @author lw
* @date 2022/3/29 0029
* @description 短信服务
*/
public class SmsService extends SenderService{
//有这个list才叫组合
private List<SenderService> senderServices = new ArrayList<>();
public SmsService(String sendType) {
super(sendType);
}
@Override
public void send() {
System.out.println("SmsService.send()--->"+this.sendType);
}
@Override
void add(SenderService senderService) {
this.senderServices.add(senderService);
}
@Override
SenderService getService(String sendType) {
for (SenderService senderService : this.senderServices) {
if(sendType.equals(senderService.sendType)){
return senderService;
}
}
return null;
}
}
这个代码和装饰器模式的AbstractSenderService对比会发现,AbstractSenderService中List是添加的其他类,而组合是自己加自己。
光这个对象是可以给外界调用,也你可以New出来,但是这体现不了List这个属性的作用。
用一个工厂初始化这个对象,内置一些组合数据。
/**
* @author lw
* @date 2022/3/30 0030
* @description
*/
public class SenderFactory {
public static SenderService produceSender(){
SenderService senderService = new SmsService("sms");
SenderService yiDongService = new SmsService("sms-yidong");
SenderService lianTongService = new SmsService("sms-liantong");
SenderService dianXinService = new SmsService("sms-dianxin");
senderService.add(yiDongService);
senderService.add(lianTongService);
senderService.add(dianXinService);
return senderService;
}
}
返回的是sms这个最大的信息,这样调用者就可以访问里面的List。
调用者
SenderService senderService = SenderFactory.produceSender();
senderService.send();
SenderService yidongService = senderService.getService("sms-yidong");
yidongService.send();
//运行后输出
SmsService.send()--->sms
SmsService.send()--->sms-yidong
通过输出可以发现,他可以选择默认的sms发送方式,也可以使用移动方式发送。
多节点组合
public static SenderService produceSender(){
SenderService senderService = new SmsService("sms");
SenderService yiDongService = new SmsService("sms-yidong");
SenderService lianTongService = new SmsService("sms-liantong");
SenderService dianXinService = new SmsService("sms-dianxin");
senderService.add(yiDongService);
senderService.add(lianTongService);
senderService.add(dianXinService);
SenderService yiDong5GService = new SmsService("sms-yidong-5g");
SenderService yiDong4GService = new SmsService("sms-yidong-4g");
SenderService yiDong3GService = new SmsService("sms-yidong-3g");
yiDongService.add(yiDong5GService);
yiDongService.add(yiDong4GService);
yiDongService.add(yiDong3GService);
return senderService;
}
修改工厂类,继续在sms-yidong下添加5g,4g,3g的发送方式。
最后如上图所示,变成一个树形结构,所以组合也常用来存储组织信息。
调用者
SenderService senderService = SenderFactory.produceSender();
senderService.send();
SenderService yidongService = senderService.getService("sms-yidong");
yidongService.send();
SenderService yidong5GService = yidongService.getService("sms-yidong-5g");
yidong5GService.send();
//运行后输出
SmsService.send()--->sms
SmsService.send()--->sms-yidong
SmsService.send()--->sms-yidong-5g
当然也可以把获取List中Service写成一个递归,这样就可以一直遍历获取到叶子节点。
@Override
SenderService getService(String sendType) {
for (SenderService senderService : this.senderServices) {
if(sendType.equals(senderService.sendType)){
return senderService;
}else{
SenderService service = senderService.getService(sendType);
if(service!=null) return service;
}
}
return null;
}
//调用处就可以直接通过根节点获取,而不需要知道内部树形长什么样子。
SenderService yidong5GService = senderService.getService("sms-yidong-5g");
yidong5GService.send();
这就是这个递归栈,有中止符号,一层层循环。
总结
记住:自己添加自己就是一个组合。
我写的最多的是Service,所以我也一般会应用到Service上,我看了其他人的设计模式博客和书,还有视频。
更多的是用一个个DTO来举例,其实在工作中DTO一般会简单定义,而不会太复杂,最多就是设计一个树形结构保存组织信息。