建造者模式(Builder pattern)—— 帮你更好的创建复杂对象
建造者模式是将一个复杂对象的构建与它的表示分离,各自独立,同样的构建过程可以有不同的表现。
一、你会怎么办?
对于复杂对象,那假如一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,你要怎样将这个类实例化?可以有两种方式:
比如我们要画一个人,这个人有头、手、脚、身体这些必选项,也有衣服、鞋子、帽子这些可选项。
public class PersonDraw1 {
// 必选属性
private String head;
private String hand;
private String foot;
private String body;
// 可选项
private String clothes;
private String shoes;
private String hat;
}
第一种:折叠构造方法模式
public class PersonDraw1 {
// 必选属性
private String head;
private String hand;
private String foot;
private String body;
// 可选项
private String clothes;
private String shoes;
private String hat;
public PersonDraw1(String head, String hand, String foot, String body) {
this.head = head;
this.hand = hand;
this.foot = foot;
this.body = body;
}
public PersonDraw1(String head, String hand, String foot, String body, String clothes) {
this.head = head;
this.hand = hand;
this.foot = foot;
this.body = body;
this.clothes = clothes;
}
public PersonDraw1(String head, String hand, String foot, String body, String clothes, String shoes) {
this.head = head;
this.hand = hand;
this.foot = foot;
this.body = body;
this.clothes = clothes;
this.shoes = shoes;
}
public PersonDraw1(String head, String hand, String foot, String body, String clothes, String shoes, String hat) {
this.head = head;
this.hand = hand;
this.foot = foot;
this.body = body;
this.clothes = clothes;
this.shoes = shoes;
this.hat = hat;
}
}
第二种:Javabean 模式
@Getter
@Setter
public class PersonDraw1 {
// 必选属性
private String head;
private String hand;
private String foot;
private String body;
// 可选项
private String clothes;
private String shoes;
private String hat;
}
第一种:调用一个类的构造函数时要决定使用哪一个,且还要考虑参数含义及顺序。
第二种:在构建过程中对象的状态容易发生变化,造成错误。
以上两种方式在创建对象时,可能造成对象不完整,少了某个属性或流程。要是少了必选项这个对象就没意义了,比如这个人缺胳膊少腿。
二、建造者模式
上面的问题,使用建造者模式可以解决。
@Getter
@ToString
public class PersonDraw {
// 必选属性
private String head;
private String hand;
private String foot;
private String body;
// 可选项
private String clothes;
private String shoes;
private String hat;
public PersonDraw(Builder builder){
this.head = builder.head;
this.hand = builder.hand;
this.foot = builder.foot;
this.body = builder.body;
this.clothes = builder.clothes;
this.shoes = builder.shoes;
this.hat = builder.hat;
}
public static class Builder {
// 必选属性
private String head;
private String hand;
private String foot;
private String body;
// 可选项
private String clothes;
private String shoes;
private String hat;
public Builder (String head, String hand, String foot, String body){
this.head = head;
this.hand = hand;
this.foot = foot;
this.body = body;
}
public Builder setClothes(String clothes){
this.clothes = clothes;
return this;
}
public Builder setShoes(String shoes) {
this.shoes = shoes;
return this;
}
public Builder setHat(String hat) {
this.hat = hat;
return this;
}
public PersonDraw build(){
return new PersonDraw(this);
}
}
}
public class Client {
public static void main(String[] args) {
PersonDraw personDraw = new PersonDraw.Builder("头", "手", "脚", "身体")
.setClothes("衣服")
.build();
Console.log(personDraw.toString());
Console.log(personDraw.getFoot());
}
}
PersonDraw(head=头, hand=手, foot=脚, body=身体, clothes=衣服, shoes=null, hat=null)
脚
- 在 PersonDraw 中创建一个静态内部类 Builder,然后将 PersonDraw 中的参数都复制到Builder类中。
- 在 PersonDraw 中创建一个private的构造函数,参数为Builder类型。
- 在Builder中创建一个构造函数,参数为 PersonDraw 中必填的那些参数。
- 在Builder中创建设置函数,对那些可选参数进行赋值,返回值为Builder类型的实例。
- 在Builder中创建一个
build()
方法,在其中构建 PersonDraw 的实例并返回。
三、建造者模式适用场景
优点:
1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
2.每一个具体建造者都独立,因此可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
3.可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰。
缺点:
1.当建造者过多时,会产生很多类,难以维护。
2.建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,若产品之间的差异性很大,则不适合使用该模式。
3.若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
适用场景:
1.创建复杂对象的算法独立于组成对象的部件
2.同一个创建过程需要有不同的内部表象的产品对象
但一般当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。