前言
为什么要用建造者模式?在我们看来他和工厂模式的目的是一样的,就是为了获取对象。下面我们进一步来了解建造者模式是什么,以及他在我们业务开发中的使用场景。
纲要
网络异常,图片无法展示
|
什么是建造者模式?
建造者模式(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对象
与工厂模式的区别
工厂模式:根据用户选择,来制作不同的食物,汉堡、面条、包子。
建造者模式:根据用户选择,来制作,加什么材料的汉堡。
- 工厂是生产某个配件,而建造者是整合配件
- 建造者注重步骤,按照步骤组装完整
- 工厂注重于创建不同对象
总结
建造者模式在我们业务开发中还是经常使用的, 他帮助我们自由组合创建对象,提高了灵活性,但是增加了代码量。