原型模式与建造者模式都属于创建型的模式,也是比较常见的模式。
1. 原型模式
原型模式常常用于复杂对象的复制,常常将需要用到原型模式的类设计成 Cloneable,这种方式实现的是浅克隆。如果需要实现深克隆,则需要将其成员对应的类也设计成 Cloneable,并进行递归,这种方式比较繁琐,通常我们使用一种简便的方式——序列化和反序列化,采用这种方式要求我们将需要序列化的类及其成员对应的类设计成 Seriable。
public class PrototypeBean implements Cloneable, Serializable {
private long id;
private String name;
private Address address;
public PrototypeBean() {}
public PrototypeBean(long id, String name) {
this(id, name, null);
}
public PrototypeBean(long id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "PrototypeBean{" +
"id=" + id +
", name='" + name + '\'' +
", address=" + address +
'}';
}
// 浅克隆
@Override
public PrototypeBean clone() throws CloneNotSupportedException {
return (PrototypeBean) super.clone();
}
// 深克隆
public PrototypeBean cloneDeeply() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(this);
} finally {
if (oos != null) oos.close();
}
ObjectInputStream ois = null;
PrototypeBean result;
try {
ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
result = (PrototypeBean) ois.readObject();
} finally {
if (ois != null) ois.close();
}
return result;
}
public static class Address implements Cloneable, Serializable {
private String nation;
private String province;
private String city;
private String detail;
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
@Override
protected Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
@Override
public String toString() {
return "Address{" +
"nation='" + nation + '\'' +
", province='" + province + '\'' +
", city='" + city + '\'' +
", detail='" + detail + '\'' +
'}';
}
}
}
2. 建造者模式
建造者模式将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
经典的应用场景如 StringBuilder 构建 String,MyBatis 中使用 SqlBuilder 构建 SQL,SpringBoot 中使用 SpringApplicationBuilder 构造 SpringApplication。
以下示例中,我们有一个表示运单的类 Waybill,该类对应一个建造者 WaybillBuilder。
public class Waybill {
// 运单号
private String billNum;
// 货物类型
private String cargoType;
// 货物名
private String cargoName;
// 货物重量
private String cargoWeight;
// 货物体积
private String cargoVolume;
// 运单费用
private String fee;
// 发件人信息
private EntityInfo sender;
// 收件人信息
private EntityInfo recipient;
public String getBillNum() {
return billNum;
}
public void setBillNum(String billNum) {
this.billNum = billNum;
}
public String getCargoType() {
return cargoType;
}
public void setCargoType(String cargoType) {
this.cargoType = cargoType;
}
public String getCargoName() {
return cargoName;
}
public void setCargoName(String cargoName) {
this.cargoName = cargoName;
}
public String getCargoWeight() {
return cargoWeight;
}
public void setCargoWeight(String cargoWeight) {
this.cargoWeight = cargoWeight;
}
public String getCargoVolume() {
return cargoVolume;
}
public void setCargoVolume(String cargoVolume) {
this.cargoVolume = cargoVolume;
}
public String getFee() {
return fee;
}
public void setFee(String fee) {
this.fee = fee;
}
public EntityInfo getSender() {
return sender;
}
public void setSender(EntityInfo sender) {
this.sender = sender;
}
public EntityInfo getRecipient() {
return recipient;
}
public void setRecipient(EntityInfo recipient) {
this.recipient = recipient;
}
// 收件人/发件人实体信息类
public static class EntityInfo {
private String name;
private String phone;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
}
public class WaybillBuilder {
private Waybill waybill;
public WaybillBuilder() {
this.waybill = new Waybill();
this.waybill.setSender(new Waybill.EntityInfo());
this.waybill.setRecipient(new Waybill.EntityInfo());
}
public WaybillBuilder setBillNum(String billNum) {
this.waybill.setBillNum(billNum);
return this;
}
public WaybillBuilder setCargoType(String cargoType) {
this.waybill.setCargoType(cargoType);
return this;
}
public WaybillBuilder setCargoName(String cargoName) {
this.waybill.setCargoName(cargoName);
return this;
}
public WaybillBuilder setCargoWeight(String cargoWeight) {
this.waybill.setCargoWeight(cargoWeight);
return this;
}
public WaybillBuilder setCargoVolume(String cargoVolume) {
this.waybill.setCargoVolume(cargoVolume);
return this;
}
public WaybillBuilder setFee(String fee) {
this.waybill.setFee(fee);
return this;
}
public WaybillBuilder setSenderName(String senderName) {
this.waybill.getSender().setName(senderName);
return this;
}
public WaybillBuilder setSenderPhone(String senderPhone) {
this.waybill.getSender().setPhone(senderPhone);
return this;
}
public WaybillBuilder setSenderAddress(String senderAddress) {
this.waybill.getSender().setAddress(senderAddress);
return this;
}
public WaybillBuilder setRecipientName(String recipientName) {
this.waybill.getRecipient().setName(recipientName);
return this;
}
public WaybillBuilder setRecipientPhone(String recipientPhone) {
this.waybill.getRecipient().setPhone(recipientPhone);
return this;
}
public WaybillBuilder setRecipientAddress(String recipientAddress) {
this.waybill.getRecipient().setAddress(recipientAddress);
return this;
}
public Waybill build() {
return this.waybill;
}
}
3. 对比
这两种设计模式都用于复杂对象的创建,前者通过对象的复制来提高对象的创建效率。后者是通过隐藏对象的创建细节(通常是比较复杂,涉及一系列固定的算法,而非简单的对成员的赋值),降低用户创建对象的难度。