考虑用构建器

遇到多个构造器参数时要考虑用构建器

java

effective java

创建和销毁对象

1. 构建器是什么?

构建器也是一种获得类对象的方法,在前面我们介绍了通过 构造器 与 静态工厂方法 两种方式来获得类的对象。
这里我们写一个 Person 类,并为这个类加上构建器:

  1. 1public class Person {


  2. 2    private final String name;

  3. 3    private final int age;

  4. 4

  5. 5    private final String address;

  6. 6    private final String phone;

  7. 7

  8. 8    public static class Builder{

  9. 9        private final String name;

  10. 10        private final int age;

  11. 11

  12. 12        private String address = null;

  13. 13        private String phone = null;

  14. 14

  15. 15        public Builder(String name,int age){

  16. 16            this.name = name;

  17. 17            this.age = age;

  18. 18        }

  19. 19

  20. 20        public Builder address(String val){

  21. 21            address = val;

  22. 22            return this;

  23. 23        }

  24. 24

  25. 25        public Builder phone(String val){

  26. 26            phone = val;

  27. 27            return this;

  28. 28        }

  29. 29

  30. 30        public Person builder(){

  31. 31            return new Person(this);

  32. 32        }

  33. 33    }

  34. 34

  35. 35    private Person(Builder builder){

  36. 36        this.name = builder.name;

  37. 37        this.age = builder.age;

  38. 38        this.address = builder.address;

  39. 39        this.phone = builder.phone;

  40. 40    }

  41. 41

  42. 42    @Override

  43. 43    public String toString() {

  44. 44        return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;

  45. 45    }

  46. 46

  47. 47}

调用这个构建器的方式

public class PersonTest {    public static void main(String[] args) {
        Person p = new Person.Builder("tom", 18).address("深圳").phone("110").builder();
        System.out.println(p.toString());
    }
}

2. 为什么使用构建器?

2.1 参数的限制

静态工厂方法与构造器都有一个共同的局限性,就是它们不能很好的扩展到大量的可选参数。就像我们上面的那个Person 类,在实际中我们会有许多的属性,性别、出生年月、爱好...对与这样的类。

2.2 重叠构造器

我们初学的时候都会选择 重叠构造器(telecoping constructor)模式 。在这种情况下,第一个构造器是实例化对象必须的参数,第二个会多一个参数,就这样叠加,最后是一个有所有参数的构造器

  1. 1public class Person {


  2. 2    private final String name;

  3. 3    private final int age;

  4. 4

  5. 5    private final String address;

  6. 6    private final String phone;

  7. 7

  8. 8    public Person(String name, int age) {

  9. 9        this(name,age,null);

  10. 10    }

  11. 11

  12. 12

  13. 13    public Person(String name, int age, String address) {

  14. 14        this(name,age,address,null);

  15. 15    }

  16. 16

  17. 17    public Person(String name, int age, String address, String phone) {

  18. 18        super();

  19. 19        this.name = name;

  20. 20        this.age = age;

  21. 21        this.address = address;

  22. 22        this.phone = phone;

  23. 23    }

  24. 24

  25. 25    @Override

  26. 26    public String toString() {

  27. 27        return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;

  28. 28    }

  29. 29

  30. 30}

获得对象

public class PersonTest {    public static void main(String[] args) {
        Person p = new Person("tom",18,null,"110");
        System.out.println(p.toString());
    }
}

在这个构造器中也许会有你不想要的参数,如果我们的参数变多了的话,情况就不会很好。
总结一句话:重叠构造器可行,但当有很多的参数的时候,客户端的代码就会很难编写并且不容易阅读我们在使用的时候,必须很仔细的看每一个参数的位置和含义。

2.3 JavaBeans模式

2.3.1 创建JavaBeans模式

这个时候我们还有一种替代的方式,这个就是JavaBeans模式。这种种模式下,使用无参的构造方法创建对象,然后调用setter 方法给属性设置值

  1. 1public class Person {


  2. 2    private String name;

  3. 3    private int age;

  4. 4

  5. 5    private String address;

  6. 6    private String phone;

  7. 7

  8. 8    public void setName(String name) {

  9. 9        this.name = name;

  10. 10    }

  11. 11    public void setAge(int age) {

  12. 12        this.age = age;

  13. 13    }

  14. 14    public void setAddress(String address) {

  15. 15        this.address = address;

  16. 16    }

  17. 17    public void setPhone(String phone) {

  18. 18        this.phone = phone;

  19. 19    }

  20. 20

  21. 21    @Override

  22. 22    public String toString() {

  23. 23        return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;

  24. 24    }

  25. 25

  26. 26}

使用的方式,这个相比与重叠构造器更容易的创建了对象,同时让代码跟容易的阅读。

public class PersonTest {    public static void main(String[] args) {
        Person p = new Person();
        p.setName("tom");
        p.setAge(18);
        p.setAddress("深圳");
        p.setPhone("110");
        System.out.println(p.toString());
    }
}

2.3.2 JavaBeans模式的劣势

  • 构造的过程分到了几个调用中,在构造JavaBeans的时候可能会不一致
  • 类无法仅仅通过检验构造器参数的有效性来保证一致性!
  • 对象的不一致会导致失败,JavaBeans模式阻止了把类做为不可变的可能,需要程序员做额外努力来保证它线程安全。

2.4 构建器

  • 构建器的创建对象就比较易于创建与阅读,线程安全
  • 等待所有的参数验证通过才会build()对象。
  • 与构造器相比,builder 的微略优势在,builder可以有多个可变(varargs)参数。构造器像方法一样,只有一个可变参数。因为builder利用单独的方法来设置每个参数,你想要多少个可变参数,他们就可以有多少个,知道每个setter方法都有一个可变参数。
  • builder模式非常灵活,可以理由单个builder构建多个对象。builder的参数可以在创建对象时进行调整
  • 设置了参数的builder生成一个很好的抽象工厂(Abstract Factory),也就是客户端可以将这样一个builder传给方法,使该方法能为客户端创建一个或者多个对象
  • builder也有自己的不足,就是创建对象就必须创建它的构建器。虽然创建构建器的开销在实践中可能不是很明显注意性能的情况先,这个就是问题了。
  • builder模式还比重叠构造器模式更加的冗长,因此它会在参数多的时候使用。但是我们要知道,我们可能会在设计之后还要添加参数,所以已开始就用构建器还是比较好的。

3 总结

如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是不错的选择,特别是当大多数参数都是可选的时候。

  • 与重叠构造器相比,builder牧师的客户端更易与阅读和编写
  • 与JavaBeans相比,更加的安全
时间: 2024-08-04 04:47:58

考虑用构建器的相关文章

构建器模式

*构建器模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.类图如下: *product产品类:表示被构建器构建的复杂对象,包含多个部件. 1 //产品接口 示意性产品,所以没有任何方法 2 public interface Product{ 3 } *builder构建器接口:定义创建一个product对象所需要的各个部件的操作. 1 //生成器接口 2 public interface Builder{ 3 public void builderPart1();

第二章:创建和销毁对象。ITEM2:遇到多个构造器参数时要考虑用构建器。

如果一个类中有大量的可选参数,有以下几种方式: 1.重叠构造器: package com.twoslow.cha2; /** * 重叠构造器可行,但是当由许多参数的时候,客户端代码很难编写. * @author sai * */ public class Item201 { private final int servingSize; private final int servings; private final int calories; private final int fat; pr

第二条 遇到多个构造器参数时,要考虑用构建器

静态工厂和构造器都有个共同的局限性,就是它们都不能够很好的扩展到大量的可选参数. 如: public class NutritionFacts{ private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public Nu

多个构造器参数使用构建器

标题一眼看过去可能不是很明白要讲什么,先来看看下面一段代码. 1 package example; 2 3 /** 4 * 重叠构造器 5 * @author yulinfeng 6 * Feb 13, 2017 7 */ 8 public class Student1 { 9 private String name; 10 private int age; 11 private String sex; 12 13 public Student1(String name) { 14 this(n

Mybatis——SQL语句构建器类

SQL语句构建器类 问题 Java程序员面对的最痛苦的事情之一就是在Java代码中嵌入SQL语句.这么来做通常是由于SQL语句需要动态来生成-否则可以将它们放到外部文件或者存储过程中.正如你已经看到的那样,MyBatis在它的XML映射特性中有一个强大的动态SQL生成方案.但有时在Java代码内部创建SQL语句也是必要的.此时,MyBatis有另外一个特性可以帮到你,在减少典型的加号,引号,新行,格式化问题和嵌入条件来处理多余的逗号或 AND 连接词之前.事实上,在Java代码中来动态生成SQL

构建器问题

class InputFile { private BufferedReader in ; // constructor InputFile(String fname) throws Exception{ try { in = new BufferedReader(new FileReader(fname)) ; // other code that might throw exceptions } catch (FileNotFoundException e) { System.out.pri

Item2: 遇到多个构造器形参时考虑使用构建器

Consider a builder when faced with many constructor parameters 引言 遇到多个构造器时要考虑用构建器(builder) 重叠构造器(telescoping constructor) // Telescoping constructor pattern - does not scale well! - Pages 11-12 /** * 营养成分表 */ public class NutritionFacts { private fin

Java 构建器

假如我们的一个实体类有很多的属性值,但是这些属性值又是可选的.如果我们遇到这样的是类,如何设计出方便的实体类呢? 通常解决办法一: 重叠构造器 public class User { private String id; // id(必填) private String name; // 用户名(必填) private String email; // 邮箱(可选) private int age; // 年龄(可选) private String phoneNumber; // 电话(可选)

构建器的调用顺序

用于基础类的构建器肯定在一个衍生类的构建器中调用,而且逐渐向上链接,使每个基础类使用的构建器都能得到调用.之所以要这样做,是由于构建器负有一项特殊任务:检查对象是否得到了正确的构建. 下面让我们看看一个例子,它展示了按构建顺序进行合成.继承以及多形性的效果: class Meal  {   Meal() { System.out.println("Meal()"); } } class Bread  {   Bread() { System.out.println("Brea

Java构建器模式

当创建对象需要传入多个参数的时候我们通常会根据参数的数量写不同的构造器,具体如下 public A(int a){} public A(int a, int b){} public A(int a, int b, int c){} 根据不同的参数调用不同的构造器,但是当参数多了的时候,这种方式不够灵活,所以会实现动态传参的方法 public A(){} public void seta(int a){} public void setb(int b){} public void setc(int