还在用构造方法给属性赋值?

如何给一个类中的属性赋值?

静态方法?构造方法?setter?

也许都不太合适,本文介绍一种推荐的方式:使用Builder构造器。

先回顾一下传统方式存在的问题。

1.构造方法和静态方法

如果有10个属性,你能记清它们的顺序吗?如下。

//创建对象时,使用构造方法给属性赋值(使用静态方法的与之类似)
public void demo(){
  Person person = new Person(1,"yanqun","颜群",170,66,"陕西西安",true,true,new String[]{"play","running","chat"},"157468995");
}

显然,乍眼一看,根本不知道里面的“170、66、...、true、true、...”是在给Person的哪个属性赋值,还得慢慢对着构造方法的定义慢慢比对。

提示:IDEA会在方法全部写完后,提示你每个参数对应的属性名,但在编写的过程中是没有提示的。

2.setter是否可行?

以上代码,如果用setter方式给对象赋值,代码如下。

//使用setter给属性赋值
public void demo02(){
    Person person = new Person();
    person.setId(1);
    person.setNickname("yanqun");
    person.setName("颜群");
    person.setHeight(170);
    person.setWeight(66);
    ...
    person.setWeiXin("157468995");
}

好像除了代码长了点以外,可读性很好。错!实际上,setter方式的最大弊端是:会造成线程不安全的隐患。

在并发环境下,假设线程A只给person的id和name属性使用setter赋了值,但如果此时线程B正好使用getter获取height、weight等其他未赋值的属性值时,就会产生person状态不一致的问题,也就是并发问题。
 

为了解决以上问题,本文推荐大家使用Builder构造器给属性赋值。

话不多说,直接上代码示例。

public class Person {
    //id和name是必填属性
    private int id ;
    private String name ;
    //其余是选填属性
    private String nickname ;
    private int height ;

    //创建Builder构造器(本例以内部类形式展现)
    public static class Builder {
        //id和name是必填属性
        private int id ;
        private String name ;
        //其余是选填属性
        private String nickname ;
        private int height ;
        //将必填属性用Builder构造方法属性
        public Builder (int id , String name){
            this.id = id;
            this.name = name;
        }
        //将其余属性通过setter方法赋值
        public Builder setNickname(String nickname){
            this.nickname = nickname;
            return this;
        }
        public Builder setHeight(int height){
            this.height = height;
            return this;
        }
        public Person build(){
            return new Person(this);
        }
    }
    private Person(Builder builder){
        this.id = builder.id;
        this.nickname = builder.nickname;
        this.name = builder.name;
        this.height = builder.height;
    }

    public static void main(String[] args) {
       Person person
               //先给必填属性赋值
               =  new Person.Builder(1,"颜群")
               //再给选填属性逐一赋值
               .setNickname("yanqun")
               .setHeight(170)
               //最后构建出person对象
               .build();
    }
}

以上在Builder构造器中,person对象是通过build()方法一次性产生的(并且person对象在产生后是 不会再发生变化的),所以保证了线程安全。并且可以通过setXxx()分别给各个属性赋值,从而也提高了可读性。从表象来看,实际很像是构造方法和setter的结合体。

并且在Builder构造器中,每一次setter返回的是this对象,因此可以轻松的实现链式编程。

简言之,在使用Builder构造器的步骤:先将必要的值通过构造方法填入,再将选填的属性通过setter注入,最后再通过build()方法生成一个最终的对象。

- 完 -

JAVA过时了吗?

自己写的java.lang.String能用吗?

synchronized有指令重排序的功能吗?

服了,list.add()也会报错!!!

10行代码2道题,全答对的你月薪多少了?

自己写的java.lang.String能用吗?

技术面试,这些坑你踩过几个?

猜你喜欢

转载自blog.csdn.net/yanqun007/article/details/103648755
今日推荐