• 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}
  • 相关阅读:
    「SAM」你的名字
    「疫期颓废」2
    「疫期颓废」1
    代码覆盖率简单介绍
    解决git报ssh variant 'simple' does not support setting port
    接口自动化基本流程和测试思路
    wait和sleep的区别
    vm垃圾回收算法的简单理解
    TCP-三次握手和四次挥手简单理解
    浏览器输入一个url 中间经历的过程
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/16426320.html
Copyright © 2020-2023  润新知