设计模式之Builder模式

来源:互联网 发布:吉他教学视频软件 编辑:程序博客网 时间:2024/05/15 10:44

情景需要:

假设有这样一个Human类,要构造一个Human对象必须传递6个参数,其中前3个是必须的,后3个是可选的:

[java] view plaincopyprint?
  1. class Human {  
  2.   
  3.     // required parameters  
  4.     private final String name;  
  5.     private final String gender;  
  6.     private final int age;  
  7.   
  8.     // optional parameters  
  9.     private final int height;  
  10.     private final int weight;  
  11.     private final String country;  
  12. }  

那么,给这个类设计构造方法会是比较头疼的事。

一种方案是,我们可以设计一个有6个参数的构造方法,分别给name, gender, height, weight, country赋值,其中后3个值可以有缺省值。如:

[java] view plaincopyprint?
  1. public Human(String name, String gender, int age, int height = 180int weight = 50, String country = "China") {  
  2.     //... ...  
  3. }  

然而这样设计有一个不足之处,那就是后3个参数虽然有缺省值,但参数的顺序是固定的,不能变的,如果用户在传参的时候把顺序搞错了,就会产生错误。而且如果参数类型相同的话,编译器也不会报错。为了弥补这样的不足,我们可以重载构造方法,如:

[java] view plaincopyprint?
  1. public Human(String name, String gender, int age) {}  
  2.   
  3. public Human(int height) {} // 不能构成重载  
  4. public Human(int weight) {} // 不能构造重载  
  5. public Human(String country) {}  

这样虽然解决了参数顺序的问题,但如果这个类的可选参数有不只3个,比如有6个,10个,20个的话,那么就要设计大量的重载的方法,非常费事。而且上面的代码还存在一个问题,那就是第2个和第3个方法根本无法构成重载。也就是说,当可选参数的参数类型有重复的时候,上面的设计方法就不可行了。


这时候我们就可以采用 Builder模式 来解决这样问题。


Builder模式

我们可以在Human的内部定义一个静态的内部类Builder,通过这个类来完成对参数的赋值工作,如:
class Human {// required parametersprivate final String name;private final String male;private final int age;// optional parametersprivate final int height;private final int weight;private final String country;// builder classpublic static class Builder {// required parametersprivate final String name;private final String male;private final int age;// optional parametersprivate int height = 0;private int weight = 0;private String country = "none";public Builder(String name, String male, int age) {this.name = name;this.male = male;this.age = age;}public Builder setHeight(int h) {this.height = h;return this;}public Builder setWeight(int w) {this.weight = w;return this;}public Builder setCountry(String c) {this.country = c;return this;}public Human build() {return new Human(this);}}}


然后为Human提供一个私有的构造方法,以Builder对象作为其形参,在此构造方法中完成参数的赋值:
[java] view plaincopyprint?
  1. private Human(Builder b) {  
  2.         name = b.name;  
  3.         gender = b.gender;  
  4.         age = b.age;  
  5.   
  6.         height = b.height;  
  7.         weight = b.weight;  
  8.         country = b.country;  
  9.     }  


这样一来,用户 在使用Human 这个类的时候,就可能以如下的方式来构造Human对象:

[java] view plaincopyprint?
  1. Human hm = new Human.Builder("bruce""male"20// 设置必须参数  
  2.             .setCountry("China"// 设置可选参数  
  3.             .setWeight(50// 设置可选参数  
  4.             .build(); // 构造对象  

显然,Human类的使用者在创建其对象时所写的代码就变得简单明了多了。


因此,当一个类的构造方法必须传递大量参数的时候,我们可以考虑使用Builder模式来构造此类。当应用程序对性能要求不是很高时,Builder模式是处理此类情形的最好方案。

原创粉丝点击