建造者(build)模式
背景
方案一:
当一个类的参数过多时,我们的常用方法一般是重叠构造器,即重载,比如有5个属性,一般我们会重载5个方法,输入参数从1到5不等。如
Dogdog = new Dog(“花花”);
Dogdog = new Dog(“花花”,1,);
Dogdog = new Dog(“花花”,1,20.0,20.0);
Dogdog = new Dog(“花花”,1,20.0,20.0,”boy”);
随着属性的增加,构造方法的参数越来越多,客户端代码也会很难编写,从可读性和设计上来看,都非常臃肿。
方案二:
遇到参数过多时,还有种替代方法就是JavaBean模式,在这种模式下,调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个可选的相关参数。
这样我们构建对象的实例一般是:
Dogdog = new Dog(“花花”);
dog.setAge(1);
dog.setWeight(20.0f);
dog.setHeigth(20.0f);
dog.setSex(“boy”);
但是Javabean模式把构造过程分散到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。另一方面,Javabean模式阻止了把类做成不可变的可能,这就需要程序员付出额外的努力来确保它的线程安全。
方案三:
幸运的是,还有第三种替代方法,既能保证像重叠构造器模式那样的安全性,也能保证像javabean模式那么好的可读性。这就是Builder模式:不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。这个builder是它构建的类的静态成员类。
实例:
Dog:
package com.mylearn.designmodel.builder;
import java.nio.DoubleBuffer;
/** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 14-1-26 * Time: 上午10:20 * CopyRight:360buy * Descrption: 建造者模式 * To change this template use File | Settings | File Templates. */ public class Dog {
private final String name; //名称 private final String sex; //性别 private final int age; //年龄 private final String fur; //毛发 private final String breed; //品种 private final float weight; //体重 private final float height; //身高
private Dog(Builder builder) { //私有构造方法,入参为内部类对象 name = builder.name; sex = builder.sex; age = builder.age; fur = builder.fur; breed = builder.breed; weight = builder.weight; height = builder.height; }
@Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", age=" + age + ", fur='" + fur + '\'' + ", breed='" + breed + '\'' + ", weight=" + weight + ", height=" + height + '}'; }
public static class Builder {
private final String name; //名称 private String sex; //性别 private int age; //年龄 private String fur; //毛发 private String breed; //品种 private float weight; //体重 private float height; //身高
public Builder(String name) { this.name = name; }
/** * 同名方法,返回this,即builder对象,方面连续build * * @param sex * @return */ public Builder sex(String sex) { this.sex = sex; return this; }
public Builder age(int age) { this.age = age; return this; }
public Builder fur(String fur) { this.fur = fur; return this; }
public Builder breed(String breed) { this.breed = breed; return this; }
public Builder weight(float weight) { this.weight = weight; return this; }
public Builder height(float height) { this.height = height; return this; }
/** * build方法,构造Dog对象,也是一种单例模式的使用方式 * * @return */ public Dog build() { return new Dog(this); } }
} |
Client:
public class Client { public static void main(String args[]) { Dog dog =new Dog.Builder("花花").age(1).height(50.0f).weight(50.0f).sex("boy").breed("拉布拉多").fur("yellow").build(); System.out.println(dog.toString()); } } |
像mongodb客户端中,morphia框架中就有很多build的应用场景
query.field("created").lessThan(date).order("created");
优劣
优点:
1. 多个可变参数
2. 客户端代码可读性非常强
缺点:
1. 增加代码量
2. 构建对象必须先创建它的构造器
总结:
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,builder模式就是种不错的选择,特别是当大多数参数都是可选的时候。