《Effective Java》第2条:遇到多个构造器参数时要考虑使用构建器

静态工厂和构造器有一个共同的局限性:不能很好地扩展到大量的可选参数

一个Book类有两个必需标签name和author,三个非必需标签price、isbn和press,对于这样的类可以采用三种方式编写:

  1. 重叠构造器
  2. JavaBeans模式
  3. 建造者模式

1. 重叠构造器 

重叠构造器提供的第一个构造器只有必要的参数,第二个构造器有一个可选参数,第三个构造器有两个可选参数,以此类推

class Book {
    private String name;
    private String author;
    private int price;
    private String isbn;
    private String press;
    public Book(String name, String author) {
        this(name, author, 0);
    }
    public Book(String name, String author, int price) {
        this(name, author, price, "");
    }
    public Book(String name, String author, int price, String isbn) {
        this(name, author, price, isbn, "");
    }
    public Book(String name, String author, int price, String isbn, String press) {
        this.name = name;
        this.author = author;
        this.price = price;
        this.isbn = isbn;
        this.press = press;
    }
}

自行调试

public class Test {
    public static void main(String[] args) {
        Book book = new Book("人生海海","麦家",0,"","北京十月文艺出版社");
    }
}

 重叠构造器可行,但是可读性差

2. JavaBeans模式 

先使用无参构造器创建对象,再调用setter方法来设置每个必要的参数 

class Book {
    private String name = "";
    private String author = "";
    private int price = 0;
    private String isbn = "";
    private String press = "";

    public Book() {
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public void setPress(String press) {
        this.press = press;
    }
}

自行调试 

public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        book.setName("人生海海");
        book.setAuthor("麦家");
        book.setPress("北京十月文艺出版社");
    }
}

可读性好,创建实例简单,但是JavaBeans模式有两个缺点

  1. 构造过程分到了几个调用中,可能出现诸如线程A正在调用set设置某对象的参数同时线程B调用get使用该对象的情况,无法保证一致性
  2. 提供setter方法使得类失去了做成不可变的可能 

3. 建造者模式 

①利用必要参数调用构造器,得到builder对象

②对builder对象调用类似setter的方法设置可选参数

③调用无参的build方法生成对象

class Book {
    private final String name;
    private final String author;
    private final int price;
    private final String isbn;
    private final String press;
    public static class Builder {
        String name;
        String author;
        int price = 0;
        String isbn = "";
        String press = "";
        public Builder(String name, String author) {
            this.name = name;
            this.author = author;
        }
        public Builder setPrice(int price) {
            this.price = price;
            return this;
        }
        public Builder setIsbn(String isbn) {
            this.isbn = isbn;
            return this;
        }
        public Builder setPress(String press) {
            this.press = press;
            return this;
        }
        public Book build() {
            return new Book(this);
        }
    }
    private Book(Builder builder) {
        this.name = builder.name;
        this.author = builder.author;
        this.price = builder.price;
        this.isbn = builder.isbn;
        this.press = builder.press;
    }

}

自行调试

public class Test{
    public static void main(String[] args) {
        Book book = new Book.Builder("人生海海","麦家").setPress("北京十月文艺出版社").build();
    }
}

builder的优势

1. 可以将多次调用某一个方法而传入的参数集中到一个域中

简单修改一下press属性及其相关方法 

class Book {
    private final String name;
    private final String author;
    private final int price;
    private final String isbn;
    private final List<String> press;
    public static class Builder {
        private final String name;
        private final String author;
        private int price = 0;
        private String isbn = "";
        private List<String> press = new ArrayList<>();
        public Builder(String name, String author) {
            this.name = name;
            this.author = author;
        }
        public Builder setPrice(int price) {
            this.price = price;
            return this;
        }
        public Builder setIsbn(String isbn) {
            this.isbn = isbn;
            return this;
        }
        public Builder addPress(String press) {
            this.press.add(press);
            return this;
        }
        public Book build() {
            return new Book(this);
        }
    }
    private Book(Builder builder) {
        this.name = builder.name;
        this.author = builder.author;
        this.price = builder.price;
        this.isbn = builder.isbn;
        this.press = new ArrayList<>(builder.press);
    }
}

连续调用两次addPress方法,可以将传入的参数集中到press里面

自行调试 

public class Test {
    public static void main(String[] args) {
        Book book = new Book.Builder("人生海海","麦家").addPress("北京十月文艺出版社").addPress("北京出版集团公司").build();
    }
}

2. 可以利用单个builder构建多个对象 

自行调试 

public class Test {
    public static void main(String[] args) {
        Book.Builder builder = new Book.Builder("人生海海","麦家").addPress("北京十月文艺出版社").addPress("北京出版集团公司");
        Book book1 = builder.build();
        Book book2 = builder.build();
    }
}

3. 自动填充某些域

创建Book对象时,为图书增加一个序列号

class Book {
    private final int count;
    private final String name;
    private final String author;
    private final int price;
    private final String isbn;
    private final List<String> press;
    public static class Builder {
        private static int count = 0;
        private final String name;
        private final String author;
        private int price = 0;
        private String isbn = "";
        private List<String> press = new ArrayList<>();
        public Builder(String name, String author) {
            this.name = name;
            this.author = author;
        }
        public Builder setPrice(int price) {
            this.price = price;
            return this;
        }
        public Builder setIsbn(String isbn) {
            this.isbn = isbn;
            return this;
        }
        public Builder addPress(String press) {
            this.press.add(press);
            return this;
        }
        public Book build() {
            count++;
            return new Book(this);
        }
    }
    private Book(Builder builder) {
        this.count = Builder.count;
        this.name = builder.name;
        this.author = builder.author;
        this.price = builder.price;
        this.isbn = builder.isbn;
        this.press = new ArrayList<>(builder.press);
    }
    public int getCount() {
        return this.count;
    }
}

自行调试 

public class Test {
    public static void main(String[] args) {
        Book.Builder builder1 = new Book.Builder("人生海海","麦家").addPress("北京十月文艺出版社").addPress("北京出版集团公司");
        Book.Builder builder2 = new Book.Builder("Effective Java","Joshua Bloch").addPress("机械工业出版社");
        Book book1 = builder1.build();
        Book book2 = builder2.build();
        Book book3 = builder1.build();
        System.out.println(book1.getCount());
        System.out.println(book2.getCount());
        System.out.println(book3.getCount());
    }
}

4. builder的参数可以在调用build方法来创建对象期间进行调整,也可以随着不同的对象而改变

builder的劣势

1. 创建对象之前必须先创建它的构建器

2. 代码更加冗长 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值