zoukankan      html  css  js  c++  java
  • effective解读-第二条 多构造参数时候使用构建器

    多参数构造器缺点:

    1. 构造参数不具名

    2. 参数多的话需要多个构造重载或者使用多个setter方法赋值

    3. JavaBean在多线程调用的时候会有线程安全问题。如一个线程还没set完值得时候,另一个线程已经使用了。

    1.普通模式

    public class Demo {
       private String filed1;
       private String filed2;
       private String filed3;
       private String filed4;
       private String filed5;
       public static class DemoBuilder {
           private final String filed1;
           private final String filed2;
           private final  String filed3;
           private final String filed4;
           private final String filed5;
           public  DemoBuilder field1(String filed1) {
               this.filed1 = filed1;
               return this;
          }

           public  DemoBuilder field2(String filed2) {
               this.filed2 = filed2;
               return this;
          }

           public  DemoBuilder field3(String filed3) {
               this.filed3 = filed3;
               return this;
          }

           public  DemoBuilder field4(String filed4) {
               this.filed4 = filed4;
               return this;
          }

           public  DemoBuilder field5(String filed5) {
               this.filed5 = filed5;
               return this;
          }
           public Demo build(){
               return new Demo(this);
          }
      }
       private Demo(DemoBuilder builder){
           this.filed1 = builder.filed1;
           this.filed2 = builder.filed2;
           this.filed3 = builder.filed3;
           this.filed4 = builder.filed4;
           this.filed5 = builder.filed5;
      }
    }

    注意:

    1. 书中构建器使用了内部类,我们也可以直接使用外部类来创建(构造权限为protected)

    2. 多个参数是多少,书中给出4个或者更多的时候

    3. Builder模式也有自身的不足,为了创建对象先创建构建器。

    2.类层次中

    package infosecuritydemo.demo;
    import java.util.EnumSet;
    import java.util.Set;

    /**
    * @author Programmer_Liu.
    * @since 2021/3/24 18:12
    */
    //上层抽象类
    public abstract class Person {
       /**
        * 内部枚举,类型
        */
       public enum Type{BLACK,YELLOW,WHITE}
       /**
        * 集合类属性,表明当前Person的类型
        */
       final Set<Type> types;

       /**
        * 通过Builder初始化外部类属性
        * 外部类是final类型,内部类的types是非final的(因为需要添加元素来最终初始化外部)
        * 所以这里使用了clone()保证对象的不可变,否则builder中再次进行build值时候会导致
        * 对象发生变化导致异常
        */
        Person(Builder<?> builder) {
           types = builder.types.clone();
      }

       /**
        * 抽象Builder
        * @param <T> 抽象类的Builder,子类Builder需要继承该Builder所以添加了递归类型参数
        */
       abstract static class Builder<T extends Builder<T>>{
           /**
            * 设置Type类型的空集合用来映射外部类的types属性
            */
           EnumSet<Type> types = EnumSet.noneOf(Type.class);

           /**
            * 链式编程方式初始化Builder映射外部类的属性
            */
           public T addType(Type type){
               types.add(type);
               return self();
          }
           abstract Person build();
           /**
            *递归类型参数,通过该方法可以获取子类自己的Builder
            */
           protected abstract T self();
      }
    }
    //下层类实现类1
    @ToString
    public class EuropePerson extends Person {
       /**
        * 内部枚举类
        */
       public enum Size {BIG, STRONGER}

       /**
        * 独有属性,体型
        */
       private final Size size;

       private EuropePerson(Builder builder) {
           //初始化继承属性
           super(builder);
           //初始化继承属性独有属性
           this.size = builder.size;
      }

       public static class Builder extends Person.Builder<Builder> {
           /**
            * 外部类映射属性
            */
           private final Size size;

           /**
            * 直接通过构建器对象初始化属性
            */
           public Builder(Size size) {
               this.size = Objects.requireNonNull(size);
          }

           //通过构建器创建外部类对象
           @Override
           EuropePerson build() {
               return new EuropePerson(this);
          }

           @Override
           protected Builder self() {
               return this;
          }
      }
    }
    //下层实现类2
    @ToString
    public class OtherPerson extends Person {

       /**
        * 独有属性
        */
       private final boolean otherField;

       /**
        * 通过构建器初始化当前类
        */
       OtherPerson(Builder builder) {
           super(builder);
           otherField = builder.otherField;
      }

       public static class Builder extends Person.Builder<Builder> {
           /**
            * 外部类字段的映射
            */
           private boolean otherField;

           /**
            * 通过链式编程的方式初始化属性
            *
            * @param otherField
            * @return
            */
           public Builder otherField(boolean otherField) {
               this.otherField = otherField;
               return this;
          }

           /**
            * 构建外部类对象
            *
            * @return
            */
           @Override
           OtherPerson build() {
               return new OtherPerson(this);
          }

           @Override
           protected Builder self() {
               return this;
          }
      }
    }

    构建对象

    public class Demo {
       public static void main(String[] args) {
           EuropePerson europePerson = new EuropePerson.Builder(EuropePerson.Size.BIG)
                  .addType(Person.Type.BLACK)
                  .addType(Person.Type.WHITE)
                  .build();

           OtherPerson otherPerson = new OtherPerson.Builder()
                  .addType(Person.Type.BLACK)
                  .addType(Person.Type.WHITE)
                  .otherField(true).build();
      }
    }

     

    作者:刘志红

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    CentOS6.10下yum安装MySQL5.7
    Nginx1.16+Tomcat8.5实现动静分离和负载均衡
    Nginx1.16下HTML页面POST请求静态JSON数据返回405状态
    Nginx1.16对图片进行防盗链
    使用Psi Probe监控Tomcat8.5
    CentOS6.10部署的Tomcat8.5启动后,浏览器访问不到的解决方法
    CentOS7.5搭建Rsync,实现文件同步
    错误 Unable to connect to a repository at URL 'svn://ip地址' 和 No repository found in 'svn://ip地址'
    CentOS7.5搭建NFS(Network File System)
    《浏览器工作原理与实践》<05>渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?
  • 原文地址:https://www.cnblogs.com/chengxuyuan-liu/p/14577313.html
Copyright © 2011-2022 走看看