builder模式
名词解释
builder表示创建,用于创建对象。
概述
Name | category | intent |
---|---|---|
builder | Creational | 提供简便的方式创建一个复杂类对象,该类可能需要有许多属性,但是并不是每个属性都是必须的。同时,创建后的对象一般不改变 |
应用在
创建复杂类对象。该对象由很多个属性构成,但是并不是每个属性都是必须的,或者是有默认
值的。同时,创建后的对象一般不改变其属性值。
在类的构造函数中,如果该类有很多属性,你需要有一个包含了所有属性的构造方法。同时为
了使用方便,你需要暴露很多只有几个属性的构造函数,剩下的属性设置默认值。比如说打
游戏时创建英雄,英雄有职业,发型,服装,性别,武器等,你的构造函数可能是这样子的:
hero(Profession p, HairColor hc, HairType ht, Cloth c, Gender g, Weapon w)
hero(HairColor hc, HairType ht, Cloth c, Weapon w) {
this(Profession WARRIOR, hc, ht,c, Gender.MALE w)
}
......
这就导致构造函数太多 ,客户端根本记不住。这就是人们所说的"telescoping constructor anti-pattern",
可伸缩构造器的反模式。这个翻译不太好理解,就简单理解为构造函数又多又臭。除了上面所说的问题外,
如果类需要加一个属性,则你的构造函数又需要加很多个。不利于扩展。
类图
代码
下面代码模拟的是一个英雄的创建过程。
package com.liang.designpattern.builder;
public enum HairColor {
WHITE, BLOND, RED, BROWN, BLACK;
@Override
public String toString() {
return name().toLowerCase();
}
}
package com.liang.designpattern.builder;
public enum HairType {
BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
"long curly");
private String title;
HairType(String title) {
this.title = title;
}
@Override
public String toString() {
return title;
}
}
package com.liang.designpattern.builder;
public enum Profession {
WARRIOR, THIEF, MAGE, PRIEST;
@Override
public String toString() {
return name().toLowerCase();
}
}
package com.liang.designpattern.builder;
public enum Weapon {
DAGGER, SWORD, AXE, WARHAMMER, BOW;
@Override
public String toString() {
return name().toLowerCase();
}
}
package com.liang.designpattern.builder;
public enum Armor {
CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
private String title;
Armor(String title) {
this.title = title;
}
@Override
public String toString() {
return title;
}
}
package com.liang.designpattern.builder;
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
package com.liang.designpattern.builder;
public class BuilderTest {
public static void main(String[] args) {
final Hero hero = new Hero.Builder(Profession.WARRIOR, "liang")
.withArmor(Armor.CHAIN_MAIL)
.withWeapon(Weapon.SWORD)
.withHairType(HairType.LONG_CURLY)
.withHairColor(HairColor.BLOND)
.build();
System.out.println(hero.getName());
}
}
真实案例
- StringBuilder,就是builder模式的使用,只不过append时所有属性值都转换char,插入到数组中;
- MongoClientOptions.Builder, 这是mongo连接的一个类,用于创建MongoClientOptions,改类保存了连接mongo时所需要的属性,所有属性都是final。
- HystrixCommand.Setter, 这是hystrix用到的用于设置熔断时所需要的参数,并利用setter生成HystrixCommand。这里面有大量builder模式的使用。