设计模式-建造者模式(Builder Pattern)
一、定义
将一个复杂对象的创建与它的表示分离,使得同样的构建过程可以创建不同的表示。
二、概念解释
复杂对象就是指一个对象有相当多的属性,如果正常创建一个有很多属性的对象,则要在构造方法里写一堆属性去设置,而有了建造者后,在对象的创建和属性设置之间就有了解耦,建造者具有对象所有的属性,并且可以做到根据一定的规则对属性进行分类设置,这样我就可以根据自己的需要通过建造者去创建各种各样属性的对象
三、场景
很多游戏都有人物初始属性的设置,比如骑马与砍杀,这款游戏在刚进入的时候就需要进行人物形体、五官、属性值的设置,其中属性值的设置最为重要,会影响到进入游戏后的发展路线(扯远了~~)。一千个玩家就有一千个奇思妙想,有的人想要各个方面都均衡,有的人就想突出某一特定属性,通过我们的建造者模式就可以很优雅的去实现
四、实现
1、类图
2、代码实现
定义我们需要初始化属性的主人公并以静态内部类形式定义建造者
@Getter
@ToString
public final class Protagonist {
private final String name;
private final BigDecimal height;
private final SkinColor skinColor;
private final Integer medicine;
private final Integer charm;
private final Integer domination;
private final Integer power;
private final Integer agile;
private final Integer luck;
private final Weapon weapon;
public Protagonist(Builder builder) {
this.name = builder.name;
this.height = builder.height;
this.skinColor = builder.skinColor;
this.medicine = builder.medicine;
this.charm = builder.charm;
this.domination = builder.domination;
this.power = builder.power;
this.agile = builder.agile;
this.luck = builder.luck;
this.weapon = builder.weapon;
}
public static class Builder {
private final String name;
private final BigDecimal height;
private final SkinColor skinColor;
private Integer medicine;
private Integer charm;
private Integer domination;
private Integer power;
private Integer agile;
private Integer luck;
private Weapon weapon;
// 基础信息 必须设置 写在构造器里
public Builder(String name, BigDecimal height, SkinColor skinColor) {
if (name == null || height == null || skinColor == null) {
throw new RuntimeException("base info not allowed null");
}
this.name = name;
this.height = height;
this.skinColor = skinColor;
}
// 辅助技能
public Builder setAuxiliaryValue(Integer medicine, Integer charm, Integer domination) {
if (medicine + charm + domination > 10) {
throw new RuntimeException("辅助技能点数和不得超过10");
}
this.medicine = medicine;
this.charm = charm;
this.domination = domination;
return this;
}
// 攻击技能
public Builder setAttackValue(Integer power, Integer agile, Integer luck) {
if (power + agile + luck > 10) {
throw new RuntimeException("攻击技能点数和不得超过10");
}
this.power = power;
this.agile = agile;
this.luck = luck;
return this;
}
// 武器
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Protagonist build() {
return new Protagonist(this);
}
}
}
主人公的属性信息
public enum SkinColor {
WHITE,
BLACK,
BROWN,
YELLOW;
}
public enum Weapon {
TWO_HANDED_SWORD,
ONE_HANDED_SWORD,
BOW_AND_ARROW,
CROSS_BOW,
LONG_POLE;
}
根据我自己的喜好创建各有所长的角色
@SpringBootTest
public class BuilderTest {
@Test
public void test() {
// 我想要一个莽夫
Protagonist simpleMindedPerson = new Protagonist.Builder("莽夫", new BigDecimal("2.50"), SkinColor.BLACK)
// 辅助技能只点统御 增加带兵数量
.setAuxiliaryValue(0, 0, 10)
// 攻击技能只点力量
.setAttackValue(10, 0, 0)
.withWeapon(Weapon.TWO_HANDED_SWORD).build();
System.out.println(simpleMindedPerson.toString());
// 我想要一个弓箭手
Protagonist archer = new Protagonist.Builder("罗宾", new BigDecimal("1.85"), SkinColor.WHITE)
// 辅助技能只点魅力
.setAuxiliaryValue(0, 10, 0)
// 攻击技能点敏捷和幸运
.setAttackValue(0, 5, 5)
.withWeapon(Weapon.BOW_AND_ARROW).build();
System.out.println(archer.toString());
}
}
五、优缺点
优点
- 优雅:对于一个复杂对象,我只需要根据我想要的属性去创建对象即可
- 一劳永逸:有了建造者,我创建不同对象就不需要写不同的构造方法或者写一个参数可观的有所有属性的构造方法
- 方便扩展:如文中例子,我按照自己需要创建了不同属性的角色,他们互相没有影响,对扩展有利
六、区别
虽然与工厂方法模式同为创建类模式,但建造者模式关注的是生成对象的细节,重点在零部件和组装上