java设计模式之构建者模式(二)
构建者模式在类的参数比较多,且很多有默认值不需要明确传参的时候非常有用。
在实际生产中上一篇关于构建者模式的博文应该已经够用。
但如果需要构建的类有父类,且希望对父子两个类的参数既要满足支持默认值也要满足覆盖默认值,还是有一定难度。
下面以项目中的一个实际案例,来演示这种情况该如何支持。
我需要构造一个任务,将他传递给任务调度中心,针对不同的任务类型,有不同的参数。当然也有公共参数。
我将公共参数,抽象出来做父类,可以看出父类的参数都是有默认值的。
TaskParameter-V1
@Data @NoArgsConstructor public class TaskParameter { //公共属性 public static final List<LocalParams> emptyList = new ArrayList<>(); public static final Map<Object, Object> emptyMap1 = new HashMap<>(); public static final Map<Object, Object> emptyMap2 = new HashMap<>(); public static final Map<Object, Object> emptyMap3 = new HashMap<>(); public static final Map<Object, Object> emptyMap4 = new HashMap<>() { private static final long serialVersionUID = -4847591983666146501L; { put("successNode", new ArrayList<>()); put("failedNode", new ArrayList<>()); } }; private Map<Object, Object> dependence = emptyMap1; private Map<Object, Object> waitStartTimeout = emptyMap2; private Map<Object, Object> switchResult = emptyMap3; private Map<Object, Object> conditionResult = emptyMap4; private List<LocalParams> localParams = emptyList; @NoArgsConstructor @Data public static class LocalParams { private String prop; private String direct; private String type; private String value; } }
对应某一类型的任务,比如DataX任务,我新建一个子类,子类继承父类,并且实现了构建者模式
DataXTaskParameter-V1
@Data @NoArgsConstructor public class DataXTaskParameter extends TaskParameter { private int customConfig; private String json; private int xms; private int xmx; public DataXTaskParameter(DataXTaskParameterBuilder builder) { this.customConfig = builder.customConfig; this.json = builder.json; this.xms = builder.xms; this.xmx = builder.xmx; } @NoArgsConstructor public static class DataXTaskParameterBuilder { private int customConfig = 1; private String json; private int xms = 1; private int xmx = 1; public DataXTaskParameterBuilder(String json) { this.json = json; } public DataXTaskParameterBuilder setCustomConfig(int customConfig) { this.customConfig = customConfig; return this; } public DataXTaskParameterBuilder setJson(String json) { this.json = json; return this; } public DataXTaskParameterBuilder setXms(int xms) { this.xms = xms; return this; } public DataXTaskParameterBuilder setXmx(int xmx) { this.xmx = xmx; return this; } public DataXTaskParameter build() { return new DataXTaskParameter(this); } } }
到这里为止,我们除了将公共默认属性抽象到了父类之外,其他的跟普通的构造这模式没有任何区别。
子类的所有属性既可以支持默认值,也支持默认值,但如果现在有一个需求,希望父类中的参数也要支持覆盖,改怎么办?
显而易见,我们需要给父类也改造成构建者模式
TaskParameter-V2
@Data @NoArgsConstructor public class TaskParameter { //公共属性 private Map<Object, Object> dependence; private Map<Object, Object> waitStartTimeout; private Map<Object, Object> switchResult; private Map<Object, Object> conditionResult; private List<LocalParams> localParams; public TaskParameter(TaskParameterBuilder builder) { this.dependence = builder.dependence; this.waitStartTimeout = builder.waitStartTimeout; this.switchResult = builder.switchResult; this.conditionResult = builder.conditionResult; this.localParams = builder.localParams; } @NoArgsConstructor @Data public static class LocalParams { private String prop; private String direct; private String type; private String value; } public static class TaskParameterBuilder { //对象和列表的默认值 public static final List<LocalParams> emptyList = new ArrayList<>(); public static final Map<Object, Object> emptyMap1 = new HashMap<>(); public static final Map<Object, Object> emptyMap2 = new HashMap<>(); public static final Map<Object, Object> emptyMap3 = new HashMap<>(); public static final Map<Object, Object> emptyMap4 = new HashMap<>() { private static final long serialVersionUID = -4847591983666146501L; { put("successNode", new ArrayList<>()); put("failedNode", new ArrayList<>()); } }; private Map<Object, Object> dependence = emptyMap1; private Map<Object, Object> waitStartTimeout = emptyMap2; private Map<Object, Object> switchResult = emptyMap3; private Map<Object, Object> conditionResult = emptyMap4; private List<LocalParams> localParams = emptyList; public TaskParameterBuilder setDependence(Map<Object, Object> dependence) { this.dependence = dependence; return this; } public TaskParameterBuilder setWaitStartTimeout(Map<Object, Object> waitStartTimeout) { this.waitStartTimeout = waitStartTimeout; return this; } public TaskParameterBuilder setSwitchResult(Map<Object, Object> switchResult) { this.switchResult = switchResult; return this; } public TaskParameterBuilder setConditionResult(Map<Object, Object> conditionResult) { this.conditionResult = conditionResult; return this; } public TaskParameterBuilder setLocalParams(List<LocalParams> localParams) { this.localParams = localParams; return this; } public TaskParameter build() { return new TaskParameter(this); } } }
但一般而言,我们不会直接构造父类的,我们只是希望在构建子类的时候能够覆盖父类的属性,显而易见,子类也需要进行升级。
子类不仅继承父类,子类的内部构造器类也继承了父类的构造器类。这样在子类中就可以更新父类的属性,达到覆盖父类默认属性的效果。
DataXTaskParameter-V2
@Data @NoArgsConstructor public class DataXTaskParameter extends TaskParameter { private int customConfig; private String json; private int xms; private int xmx; public DataXTaskParameter(DataXTaskParameterBuilder builder) { super(builder); this.customConfig = builder.customConfig; this.json = builder.json; this.xms = builder.xms; this.xmx = builder.xmx; } @NoArgsConstructor public static class DataXTaskParameterBuilder extends TaskParameterBuilder{ private int customConfig = 1; private String json; private int xms = 1; private int xmx = 1; public DataXTaskParameterBuilder(String json) { this.json = json; } public DataXTaskParameterBuilder setCustomConfig(int customConfig) { this.customConfig = customConfig; return this; } public DataXTaskParameterBuilder setJson(String json) { this.json = json; return this; } public DataXTaskParameterBuilder setXms(int xms) { this.xms = xms; return this; } public DataXTaskParameterBuilder setXmx(int xmx) { this.xmx = xmx; return this; } public DataXTaskParameter build() { return new DataXTaskParameter(this); } } }
测试一下:
class DataXTaskParameterTest { @Test void test() { DataXTaskParameter.DataXTaskParameterBuilder builder1 = new DataXTaskParameter.DataXTaskParameterBuilder(); DataXTaskParameter build1 = builder1.setJson("read & writer").build(); String s1 = JSONObject.toJSONString(build1, SerializerFeature.WriteMapNullValue); System.out.println(s1); DataXTaskParameter.DataXTaskParameterBuilder builder2 = new DataXTaskParameter.DataXTaskParameterBuilder(); DataXTaskParameter build2 = (DataXTaskParameter) builder2 .setJson("read & writer") .setXms(2) .setDependence(new HashMap<>(){{put("A","1");}}) .build(); String s2 = JSONObject.toJSONString(build2, SerializerFeature.WriteMapNullValue); System.out.println(s2); } }
输出:
{"conditionResult":{"successNode":[],"failedNode":[]},"customConfig":1,"dependence":{},"json":"read & writer","localParams":[],"switchResult":{},"waitStartTimeout":{},"xms":1,"xmx":1}
{"conditionResult":{"successNode":[],"failedNode":[]},"customConfig":1,"dependence":{"A":"1"},"json":"read & writer","localParams":[],"switchResult":{},"waitStartTimeout":{},"xms":2,"xmx":1}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南