【设计模式 】| 建造者源码学习与实践
站长
· 阅读数 4
前言
为什么要用建造者模式?在我们看来他和工厂模式的目的是一样的,就是为了获取对象。下面我们进一步来了解建造者模式是什么,以及他在我们业务开发中的使用场景。
纲要
什么是建造者模式?
建造者模式(Builder Pattern):将复杂对象的构造与其表示分离,以便同一构造过程可以创建不同的表示。
优缺点
四大主要角色
为什么要用建造者模式?
从两点来考虑
- 分阶段、分步骤的方法更适合多次运算结果类创建场景
- 不需要关心特定类型的建造者的具体算法实现
封装的变化
- 建造器的数量与具体实现
- 建造器内部创建多个属性
- 建造器的步骤
常用场景
实现Bean对象的构建
//建造者的抽象基类(接口)
public interface Builder<T> {
T build();
}
//最终构建的对象
public class User {
private boolean isRef;
private Object name;
private String cardId;
public Object getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", cardId='" + cardId + '\'' +
'}';
}
private User(BuilderImpl builder){
this.name = builder.name;
this.cardId = builder.cardId;
}
private static BuilderImpl builder(){
return new BuilderImpl();
}
// Builder 类的具体实现类 && 指挥者
private static class BuilderImpl implements Builder<User> {
private Object name;
private String cardId;
private boolean isRef;
private BuilderImpl name(Object name){
this.name = name;
return this;
}
private BuilderImpl cardId(String cardId){
this.cardId = cardId;
return this;
}
private BuilderImpl isRef(boolean isRef){
this.isRef = isRef;
return this;
}
//指挥者,得到一个新的User对象
@Override
public User build(){
if (!this.isRef){
if (this.name == null || this.cardId == null){
throw new NullPointerException();
}
}else {
if (!(this.name instanceof String)){
throw new IllegalArgumentException("name必须为String类型");
}
}
return new User(this);
}
}
public static void main(String[] args) {
User u = User.builder().isRef(true).name(213).cardId("cardId").build();
System.out.println(u);
}
}
上面的实现逻辑,就是Lombok注释中,@Builder的大概实现,我们可以通过set方法设置建造者的变量值,自由组合来完成一个新的对象,
在结尾的build()方法中集中进行数据的校验。
源码学习案例
-
JDK 类库中的 Appendable 接口
-
StringBuilder
建造者的抽象基类(接口)
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
Builder 类的具体实现类
abstract class AbstractStringBuilder implements Appendable, CharSequence {
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
// Documentation in subclasses because of synchro difference
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
}
指挥者与具体的建造者
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
}
通过上面的代码可以看出他们之间的关系
- Appendable作为基类,提供三个方法
- AbstractStringBuilder实现了三个方法
- 在StringBuilder中继承了AbstractStringBuilder类,重写父类的方法,履行指导者的作用,调用append方法,返回一个StringBuilder对象
与工厂模式的区别
工厂模式:根据用户选择,来制作不同的食物,汉堡、面条、包子。
建造者模式:根据用户选择,来制作,加什么材料的汉堡。
- 工厂是生产某个配件,而建造者是整合配件
- 建造者注重步骤,按照步骤组装完整
- 工厂注重于创建不同对象
总结
建造者模式在我们业务开发中还是经常使用的, 他帮助我们自由组合创建对象,提高了灵活性,但是增加了代码量。