1.概念
定义:建造者模式是把一个物体的构造过程与其本身进行分离,使得相同的构造过程可以创建不同的物体,简而言之,就是构造过程复用。
想象一下我们玩角色扮演类游戏的时候,刚开始电脑会让你创建角色,比如选择人物的职业、头发颜色、性别,最后输入一个骚气的昵称,这个创建的过程就算完成了!
2.为什么要用这个建造者模式呢
答:它是一种创建对象的软件设计模式,旨在提高对象构造器的伸缩性。
不用这个模式,我们的对象伸缩性瓶颈是哪里呢?看下面的代码就会明白:
public Hero(Profession profession, String name) {
}
如您所见,构造函数参数的数量如果再增加,那么很快就会失控,因为同样类型的参数,我们可能难以理解参数的排列。另外,如果将来想添加更多选项,则此参数列表可能会继续增长。这也被称为伸缩构造函数反模式。
3.程式范例
还是以游戏中创建英雄的例子来说吧,先来完成我们英雄的一些初始化属性。
/**
* 职业的枚举类
*
* @author suvue
* @date 2020/1/12
*/
public enum Profession {
/**
* 战士
*/
WARRIOR,
/**
* 刺客
*/
THIEF,
/**
* 法师
*/
MAGE,
;
@Override
public String toString() {
return name().toLowerCase();
}
}
下面是英雄的头发颜色枚举。
/**
* 头发颜色
*
* @author suvue
* @date 2020/1/12
*/
public enum HairColor {
/**
* 红发
*/
RED,
/**
* 棕发
*/
BROWN,
/**
* 黑发
*/
BLACK,
;
@Override
public String toString() {
return name().toLowerCase();
}
}
下面是英雄持有的武器枚举了。
import lombok.Data;
/**
* 英雄
*
* @author suvue
* @date 2020/1/12
*/
@Data
public class Hero {
private final HairColor hairColor;
private final Profession profession;
private final Weapon weapon;
private final String name;
/**
* 我们传进来一个通用的建造器
*/
public Hero(Builder builder) {
this.hairColor = builder.hairColor;
this.profession = builder.profession;
this.weapon = builder.weapon;
this.name = builder.name;
}
/**
* 这是一个静态内部类,我们来实现这个通用建造器
*/
public static class Builder {
private HairColor hairColor;
private final Profession profession;
private Weapon weapon;
private final String name;
/**
* 建造器的构造函数 我们要求职业和昵称必填
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("初始化参数为空");
}
this.profession = profession;
this.name = name;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
我们来看看具体是怎么使用的吧
public class Client {
public static void main(String[] args) {
//创建一个拿着法杖的红发魔法师角色
Hero mage = new Hero
.Builder(Profession.MAGE, "法师")
.withHairColor(HairColor.RED)
.withWeapon(Weapon.ROD)
.build();
System.out.println(mage.toString());
//创建一个拿着剑的黑发战士角色
Hero warrior = new Hero.Builder(Profession.WARRIOR, "战士")
.withHairColor(HairColor.BLACK)
.withWeapon(Weapon.SWORD)
.build();
System.out.println(warrior.toString());
}
}
创建过程是不是很简单呢,而且以后要是扩展的话,直接在Hero类中加一个类似于withWeapon()的方法就行啦
前辈们总结的经验,都乃是精髓呀!
4.建造者模式在框架中的使用
4.1JDK1.8源码中的建造者模式
StringBuilder与StringBuffer的父抽象类:AbstractStringBuilder 我们截取一部分关键源码看一下。
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
4.2 spring中的建造者模式
摘选 BeanDefinitionBuilder 类的部分源码。
package org.springframework.beans.factory.support;
public final class BeanDefinitionBuilder {
//获取builder对象的静态方法
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
public BeanDefinitionBuilder setParentName(String parentName) {
this.beanDefinition.setParentName(parentName);
return this;
}
public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
this.beanDefinition.setFactoryMethodName(factoryMethod);
return this;
}
public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
this.beanDefinition.setFactoryMethodName(factoryMethod);
this.beanDefinition.setFactoryBeanName(factoryBean);
return this;
}
//可以有很多个set方法灵活性的为属性赋值
//...
}