当构造方法参数过多时使用build模式
Posted origalom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当构造方法参数过多时使用build模式相关的知识,希望对你有一定的参考价值。
静态工厂方法和构造方法都有同一个缺陷:当可选参数过多时,它们都没有办法很好的进行扩展。所以,当参数过多时,一般采用的方法有:可伸缩构造方法模式(the telescoping constructor pattern)、javaBeans模式和Builder模式。
1、telescoping constructor模式
(1)如何使用
在telescoping constructor模式中,首先提供一个必需参数的构造方法,然后再加一个可选参数形成第二个构造方法,接着再加一个可选参数形成第三个构造方法,等等,直到构造方法中包含所有的可选参数。例如:
1 public class Person { 2 private String name; // 必需 3 private String nickname; // 必需 4 private int age; // 可选 5 private String phone; // 可选 6 7 public Person(String name, String nickname) { 8 this(name, nickname, 0); 9 } 10 11 public Person(String name, String nickname, int age) { 12 this(name, nickname, age, null); 13 } 14 15 public Person(String name, String nickname, int age, String phone) { 16 this.name = name; 17 this.nickname = nickname; 18 this.age = age; 19 this.phone = phone; 20 } 21 }
实例化方法:Person p = new Person("张三", "小小");
(2)缺点
-
- 当对象实例化时,你可能会需要对你不想设置的参数传值
- 当参数很多时,客户端代码很难编写,也很难进行阅读
2、JavaBeans模式
(1)如何使用
在JavaBeans模式中,先调用一个无参构造方法创建对象,然后调用类中的setter方法设置参数。例如:
1 public class Person { 2 private String name; // 必需 3 private String nickname; // 必需 4 private int age; // 可选 5 private String phone; // 可选 6 7 public Person() {} 8 9 public void setName(String name) { 10 this.name = name; 11 } 12 13 public void setNickname(String nickname) { 14 this.nickname = nickname; 15 } 16 17 public void setAge(int age) { 18 this.age = age; 19 } 20 21 public void setPhone(String phone) { 22 this.phone = phone; 23 } 24 }
实例化方法: Person p = new Person();
p.setName("张三");
p.setNickname("小小");
(2)缺点
由于构造方法在多次调用中被分割,所以JavaBeans模式是线程不安全的,在多线程模式下,对象的值可能会发生变化。
3、Builder模式
(1)如何使用
builder模式结合了telescoping constructor模式的安全性和JavaBeans模式的可读性。客户端不直接调用所需对象,而是使用所有必须参数的构造方法(或静态工厂方法)来获取一个bulider对象;然后客户端调用builder对象的和setter相似的方法来设置每个可选参数;最后,客户端调用一个无参的builder方法来生成一个对象。
1 public static class Pizza { 2 public enum Topping {HAM, MUSHROOM, ONION} 3 final Set<Topping> toppings; 4 5 abstract static class Builder<T extends Builder<T>> { 6 EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class); 7 public T addTopping(Topping topping) { 8 toppings.add(topping); 9 return self(); 10 } 11 abstract Pizza build(); 12 13 protected abstract T self(); 14 } 15 16 Pizza(Builder<?> builder) { 17 toppings = builder.toppings.clone(); 18 } 19 } 20 21 public class MyPizza extends Pizza { 22 public enum Size{SMALL, MEDIUM, LARGE} 23 private final Size size; 24 25 public static class Builder extends Pizza.Builder<Builder> { 26 private final Size size; 27 28 public Builder(Size size) { 29 this.size = size; 30 } 31 32 @Override 33 public MyPizza build() { 34 return new MyPizza(this); 35 } 36 37 @Override 38 protected Builder self() { 39 return this; 40 } 41 } 42 43 private MyPizza(Builder builder) { 44 super(builder); 45 size = builder.size; 46 } 47 }
实例化方法:MyPizza pizza = new MyPizza.Builder(SMALL).addTopping(SAUAGE).build();
(2) 缺点
为了创建对象,必须先创建对象的builder,所以在关键的时候,性能会有稍许影响,而且builder模式的构建比较麻烦。
4、总结
当设计类的构造方法或静态工厂的参数超过几个时,Builder模式是一个不错的选择,特别是如果许多参数是可选的或相同类型的。
以上是关于当构造方法参数过多时使用build模式的主要内容,如果未能解决你的问题,请参考以下文章