我是一个粉刷匠,粉刷本领强。我要把那新房子,刷得更漂亮。请问如何评价一个粉刷匠刷墙的质量,就是要求刷的地方不留白且均匀,也就是对细节的把控上。今天介绍的建造者模式,它就是根据对象的每个细节来建造,落实到对象每一个属性上。
假如现在我们要构建一个会员对象,该会员对象有以下属性:
会员名称、会员等级、会员折扣(打几折)
那么我们该如何构建该对象?遇到这个问题其实我们最能想到的是什么方法,就是构造方法,最终就会实现一个如下效果。
Member member = new Member("普通会员", 5, 6);
那么这种传统的构造方法有什么问题呢。
1. 可读性差
上边的例子中,名称你或许很容易就能知道,但会员等级、折扣呢,只有到了对应的构造方法后才能确定张三的会员等级、折扣。
2. 不灵活
后期我想在加上一个会员权限,这个怎么加呢?有些属性是必要的,而有些属性不是必要的,我们又该如何构建。
聪明的你或许会想到用get/set,它确实能解决问题,但这样做就没有弊端了吗,它没有办法一次性构建完整对象,只能分步设置,这样很容易出错。
正因为传统的构造方法和get/set在构建复杂对象有很多问题,由此衍生出了建造者模式,它适用于当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数时的情况。
------------------------------------------------------------------------------------------------
接下来就给大家介绍下建造者模式。
它首先有如下四个角色:
- Product: 最终要生成的对象,例如 Member实例。
- Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法
Product getProduct()
。 - ConcreteBuilder: Builder的实现类。
- Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法
void Construct(Builder builder)
, 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的getProduct()
方法获得最终的产品。
废话少叙,直接上代码:
public class BuilderTest {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Member normalMember = director.normalConstruct();
System.out.println(normalMember.toString());
Member advancedMember = director.advancedConstruct();
System.out.println(advancedMember.toString());
//剔除导演类
Builder builder1 = new ConcreteBuilder();
builder1.buildNormalMember();
Member result = builder1.getProduct();
System.out.println(result);
}
}
// Builder
abstract class Builder{
//创建产品对象
protected Member member = new Member();
public abstract void buildNormalMember();
public abstract void buildAdvancedMember();
public Member getProduct(){
return member;
}
}
// ConcreteBuilder
class ConcreteBuilder extends Builder{
@Override
public void buildNormalMember() {
member.setName("普通会员");
member.setLevel(1);
member.setDiscount(9);
member.setPermission(2);
}
@Override
public void buildAdvancedMember() {
member.setName("高级会员");
member.setLevel(2);
member.setDiscount(8);
member.setPermission(1);
}
}
class Director{
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public Member normalConstruct(){
builder.buildNormalMember();
return builder.getProduct();
}
public Member advancedConstruct(){
builder.buildAdvancedMember();
return builder.getProduct();
}
}
// Product:最终要生成的对象
class Member{
// 会员名称
private String name;
// 会员等级
private Integer level;
// 会员折扣
private Integer discount;
// 会员权限
private Integer permission;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
public Integer getDiscount() {
return discount;
}
public void setDiscount(Integer discount) {
this.discount = discount;
}
public Integer getPermission() {
return permission;
}
public void setPermission(Integer permission) {
this.permission = permission;
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", level=" + level +
", discount=" + discount +
", permission='" + permission +
'}';
}
}
运行结果如下:
Member{name='普通会员', level=1, discount=9, permission=2}
Member{name='高级会员', level=2, discount=8, permission=1}
// 剔除导演类
Member{name='普通会员', level=1, discount=9, permission=2}
在传统的建造者模式中,它把构造的细节进行了封装(必要参数),这样我们只需要在使用的时候调用对应的方法进行对象构建即可,方便了后续的扩展。
可能你又有疑问了,我在很多源码上看到的建造者模式长这样呀,如下:
Product product=new Product.Builder("XX")
.setXXX("XXX")
.setXXXX("XXXX")
.build();
其实它算是传统建造者模式的变种,它省略了director 这个角色,将构建算法交给了client端,并将builder 写到了要构建的产品类里面,最后采用了链式调用。
代码如下:
public class Client{
public static void main(String[] args) {
Member member = new Member.Builder("普通会员", 1)
.setDiscount(9)
.setPermission(2)
.build();
System.out.println(member.toString());
}
}
class Member {
// 会员名称
private String name; // 必须
// 会员等级
private Integer level; // 必须
// 会员折扣
private Integer discount; // 可选
// 会员权限
private Integer permission; // 可选
public Member(Builder builder) {
this.name = builder.name;
this.level = builder.level;
this.discount = builder.discount;
this.permission = builder.permission;
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", level=" + level +
", discount=" + discount +
", permission=" + permission +
'}';
}
public static class Builder{
// 会员名称
private String name; // 必须
// 会员等级
private Integer level; // 必须
// 会员折扣
private Integer discount; // 可选
// 会员权限
private Integer permission; // 可选
public Builder(String name,Integer level){
this.name = name;
this.level = level;
}
public Member.Builder setDiscount(int discount) {
this.discount = discount;
return this;
}
public Member.Builder setPermission(Integer permission) {
this.permission = permission;
return this;
}
public Member build(){
return new Member(this);
}
}
}
运行结果如下:
Member{name='普通会员', level=1, discount=9, permission=2}
我们要根据真实的业务场景灵活选用。
结束!