Builder模式
前言
构建对象时,如果碰到类有很多参数——其中很多参数类型相同而且很多参数可以为空时,推荐Builder模式来完成。当参数数量不多、类型不同而且都是必须出现时,通过增加代码实现Builder往往无法体现它的优势。在这种情况下,理想的方法是调用传统的构造函数。再者,如果不需要保持不变,那么就使用无参构造函数调用相应的set方法吧。
普通方式,通过构造方法创建实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.ubuntuvim.pattern.builder;
public class Car {
private String carBody; private String tyre; private String engine; private String aimingCircle;
private String decoration;
public Car(String carBody, String tyre, String engine, String aimingCircle) { super(); this.carBody = carBody; this.tyre = tyre; this.engine = engine; this.aimingCircle = aimingCircle; }
public Car(String carBody, String tyre, String engine, String aimingCircle, String decoration) { super(); this.carBody = carBody; this.tyre = tyre; this.engine = engine; this.aimingCircle = aimingCircle; this.decoration = decoration; }
@Override public String toString() { return "Car [carBody=" + carBody + ", tyre=" + tyre + ", engine=" + engine + ", aimingCircle=" + aimingCircle + ", decoration=" + decoration + "]"; } }
|
这是最常见的、最普通的方式——通过构造方法传递属性,并创建实例。
简单使用main方法模拟调用。
1 2 3 4 5 6 7 8 9 10 11 12
| package com.ubuntuvim.pattern.builder;
public class Client { public static void main(String[] args) { Car c = new Car("carBody", "tyre", "engine", "aimingCircle"); System.out.println(c); } }
|
这种方式简单,但是参数多的情况传参麻烦,并且参数次序不能错,否则得到的实例不是自己想要的。
JavaBean方式创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| package com.ubuntuvim.pattern.builder;
public class Car2 {
private String carBody; private String tyre; private String engine; private String aimingCircle;
private String decoration;
public void setCarBody(String carBody) { this.carBody = carBody; }
public void setTyre(String tyre) { this.tyre = tyre; }
public void setEngine(String engine) { this.engine = engine; }
public void setAimingCircle(String aimingCircle) { this.aimingCircle = aimingCircle; }
public void setDecoration(String decoration) { this.decoration = decoration; }
@Override public String toString() { return "Car2 [carBody=" + carBody + ", tyre=" + tyre + ", engine=" + engine + ", aimingCircle=" + aimingCircle + ", decoration=" + decoration + "]"; } }
|
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.ubuntuvim.pattern.builder;
public class Client { public static void main(String[] args) { Car c = new Car("carBody", "tyre", "engine", "aimingCircle"); System.out.println(c); Car2 c2 = new Car2(); c2.setCarBody("carBody2"); c2.setTyre("tyre2"); c2.setEngine("engine2"); c2.setAimingCircle("aimingCircle2"); System.out.println(c2);
} }
|
提供无参的构造函数,暴露一些公共的方法让用户自己去设置对象属性,这种方法较之第一种似乎增强了灵活度,用户可以根据自己的需要随意去设置属性。但是这种方法自身存在严重的缺点:
- 因为构造过程被分到了几个调用中,在构造中 JavaBean 可能处于不一致的状态。类无法仅仅通过判断构造器参数的有效性来保证一致性。
- 参数无法校验,本例子中
carBody
、tyre
、engine
、aimingCircle
这几个属性是必须的。Javabean的方式无法校验。
Builder模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| package com.ubuntuvim.pattern.builder;
public final class Car3 {
private String carBody; private String tyre; private String engine; private String aimingCircle;
private String decoration;
public Car3(Builder builder) { this.aimingCircle = builder.aimingCircle; this.carBody = builder.carBody; this.decoration = builder.decoration; this.engine = builder.engine; this.tyre = builder.tyre; }
public static final class Builder {
private String carBody; private String tyre; private String engine; private String aimingCircle;
private String decoration;
public Builder() { } public Builder setCarBody(String carBody) { this.carBody = carBody; return this; } public Builder setTyre(String tyre) { this.tyre = tyre; return this; } public Builder setEngine(String engine) { this.engine = engine; return this; } public Builder setAimingCircle(String aimingCircle) { this.aimingCircle = aimingCircle; return this; } public Builder setDecoration(String decoration) { this.decoration = decoration; return this; }
public Car3 build() throws Exception { if (this.carBody == null) throw new Exception("carBody不允许为空。"); if (this.aimingCircle == null) throw new Exception("aimingCircle不允许为空。"); if (this.tyre == null) throw new Exception("tyre不允许为空。"); return new Car3(this); } } @Override public String toString() { return "Car3 [carBody=" + carBody + ", tyre=" + tyre + ", engine=" + engine + ", aimingCircle=" + aimingCircle + ", decoration=" + decoration + "]"; } }
|
调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.ubuntuvim.pattern.builder;
public class Client { public static void main(String[] args) throws Exception { Car c = new Car("carBody", "tyre", "engine", "aimingCircle"); System.out.println(c); Car2 c2 = new Car2(); c2.setCarBody("carBody2"); c2.setTyre("tyre2"); c2.setEngine("engine2"); c2.setAimingCircle("aimingCircle2"); System.out.println(c2); Car3 c32 = new Car3.Builder() .setAimingCircle("奔驰") .setCarBody("奔驰") .setEngine("奔驰") .setTyre("奔驰") .build(); System.out.println(c32);
Car3 c33 = new Car3.Builder() .setAimingCircle("奔驰") .setCarBody("奔驰") .setEngine("奔驰") .setTyre("奔驰") .setDecoration("可选属性:高级音响") .build(); System.out.println(c33);
Car3 c3 = new Car3.Builder().build(); System.out.println(c3); } }
|
首先参数的设置包含了javabean的特点,不需要关注参数的次序并且可以链式设置,代码更优雅;其次,可以校验一些必须的参数。
以上就是Builder模式。