1.前言
单例模式可以创建出一个实例,并且这个实例存在的情况下,不会再创建出同样的实例。但是,有个明显的缺点,就是扩展性不高。实际开发中经常会遇到另外一种创建对象的情况,根据用户需求对实例进行设置。若放在构造函数中,要么加判断语句,要么重载构造函数,很不灵活;若通过setter注入,会增加许多与功能不相关的方法,而且对象的设置一般放在初始化时,不能让用户随时修改。
2.概念
建造者模式将一个复杂对象的构建与它的表示分离,使得对象专注于功能的展示,隐藏内部的实现。需要注意的是,一旦创建了对象,就不可修改配置了。还有最容易被误解的第二句,同样的构建过程可以创建不同的表示,即创建对象的算法应该独立于它的装配方式,允许创建结果有不同表示。
3.场景
食品厂准备生产月饼,需要根据市场喜好制作一套模具。然后,通过模具给月饼胚子成形,表面印上花纹。这里需要注意的是,我们可以新建不同的模具,让食品厂生产不同的月饼。
4.写法
public final class Mooncakes {
// 1.创建的对象所具有的属性
private int mSize;
private String mName;
private Mooncakes(int size, String name) {
super();
mSize = size;
mName = name;
}
// 2.创建的对象所表现的功能
public void product() {
System.out.println("开始生产 " + mSize + "号大小 " + " " + mName + "花纹的月饼");
}
public static class Builder {
// 3.构造器存储对象的属性
private int mSize = 10;
private String mName = "";
// 4.向构造器设置对象的属性
public Builder setSize(int size) {
if (size > 0) {
mSize = size;
}
return this;
}
public Builder setName(String name) {
if (name != null && !name.equals("")) {
mName = name;
}
return this;
}
// 5.通过构造器构造对象
public Mooncakes build() {
return new Mooncakes(mSize, mName);
}
}
}
public class Company {
public static void main(String[] args) {
// 先制作模具,在生产月饼
new Mooncakes.Builder().setSize(4).setName("嫦娥").build().product();
new Mooncakes.Builder().setName("嫦娥").build().product();
new Mooncakes.Builder().setSize(4).build().product();
}
}
不知道,大家可有发现一个问题。虽然一个具体的模具与一种月饼绑定,但是模具的制作没有规范,比较随意,不符合实际。所以,我们得关注第二点概念。这里有一些误区,大家可以参考happyhippy的文章,看最后的核心思想就够了,毕竟我们讨论的前提是算法不变。Director 定义了模具的制作规范,具体怎么实施由Builder实现类决定。
// 1.构造复杂对象默认实例
public class Mooncakes {
private int mSize;
private String mName;
public Mooncakes() {
super();
mSize = 10;
mName = "";
}
public void setmSize(int mSize) {
this.mSize = mSize;
}
public void setmName(String mName) {
this.mName = mName;
}
@Override
public String toString() {
return "Mooncakes [mSize=" + mSize + ", mName=" + mName + "]";
}
}
// 2.导向器,定义复杂对象的构建算法
public class Director {
private Builder mBuilder;
public Director(Builder builder) {
super();
mBuilder = builder;
}
// 对于月饼而言,步骤是不会变的,先定型后印花
public Mooncakes produceMooncakes() {
return mBuilder.setSize(4).setName("嫦娥").build();
}
}
// 3.抽象出对象的组装方式
public abstract class Builder {
protected Mooncakes mCakes = new Mooncakes();
public abstract Builder setSize(int size);
public abstract Builder setName(String name);
public Mooncakes build() {
return mCakes;
}
}
// 4.按照正常的方式设置
public class NormalBuilder extends Builder {
@Override
public Builder setSize(int size) {
if (size > 0) {
mCakes.setmSize(size);
}
return this;
}
@Override
public Builder setName(String name) {
if (name != null && !name.equals("")) {
mCakes.setmName(name);
}
return this;
}
}
// 5.按照我的方式设置
public class LanceBuilder extends Builder {
@Override
public Builder setSize(int size) {
if (size > 0) {
mCakes.setmSize(size * 2);
}
return this;
}
@Override
public Builder setName(String name) {
if (name != null && !name.equals("")) {
mCakes.setmName("欢乐" + name);
}
return this;
}
}
public class Company{
public static void main(String[] args) {
// 先制作模具,在生产月饼
Mooncakes normalCakes = new Director(new NormalBuilder()).produceMooncakes();
Mooncakes lanceCakes = new Director(new LanceBuilder()).produceMooncakes();
System.out.println(normalCakes.toString());
System.out.println(lanceCakes.toString());
}
}
5.总结
建造者模式在安卓开发中较为常见,主要是调用系统的控件,比如说Dialog、Notification等需要做大量自定义设置的。由于通过链式调用,使得代码简洁易懂,将封装与扩展很好地结合起来。当然,缺点也很明显,多了不少类。