1. 模式简介
原型实例指定创建对象的种类,通过克隆这些原型创建新的对象。调用者不需要指定对象的创建细节,不通过调用构造函数创建对象。属于创建型设计模式。
2. 示例代码
2.1. 浅克隆
2.1.1. 代码实现
- 原型接口
/**
* <p>
* 钱
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:53
*/
public interface Money {
/**
* 打印
*
* @return {@link Money}
*/
Money print();
}
- 具体实现
/**
* <p>
* 形状
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:59
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Shape implements Serializable {
/**
* 描述
*/
private String desc;
}
/**
* <p>
* 一百元
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:56
*/
@Getter
@Setter
public class HundredMoney implements Money {
private Shape shape;
/**
* 打印
*
* @return {@link Money}
*/
@Override
public Money print() {
HundredMoney hundredMoney = new HundredMoney();
hundredMoney.setShape(this.shape);
return hundredMoney;
}
}
- 测试类
/**
* <p>
* 原型模式,浅克隆测试
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 16:35
*/
public class PatternTest {
public static void main(String[] args) {
HundredMoney money1 = new HundredMoney();
money1.setShape(new Shape("纸币"));
// 原型模式 浅克隆
HundredMoney money2 = (HundredMoney) money1.print();
System.out.println("money1 -> 引用对象地址:" + money1.getShape());
System.out.println("money2 -> 引用对象地址:" + money2.getShape());
System.out.println("引用对象地址比较:" + (money1.getShape() == money2.getShape()));
}
}
- 测试结果
money1 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@1d44bcfa
money2 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@1d44bcfa
引用对象地址比较:true
2.1.2. UML图例
2.2. 深克隆
深克隆一定需要实现
Serializable接口
2.2.1. 代码实现
- 原型接口
/**
* <p>
* 钱
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:53
*/
public interface Money {
/**
* 打印
*
* @return {@link Money}
*/
Money print();
}
- 具体实现
/**
* <p>
* 形状
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:59
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Shape implements Serializable {
/**
* 描述
*/
private String desc;
}
/**
* <p>
* 一百元
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:56
*/
@Getter
@Setter
public class HundredMoney implements Money, Cloneable, Serializable {
private Shape shape;
/**
* 打印
*
* @return {@link Money}
*/
@Override
public Money print() {
return (Money) this.clone();
}
@Override
protected Object clone() {
return this.deepClone();
}
@SneakyThrows
private Object deepClone() {
@Cleanup ByteArrayOutputStream bos = new ByteArrayOutputStream();
@Cleanup ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
@Cleanup ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
@Cleanup ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
- 测试类
/**
* <p>
* 原型模式,深克隆测试,注意所有引用对象均需要实现 {@link java.io.Serializable} 接口
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 17:29
*/
public class PatternTest {
public static void main(String[] args) {
HundredMoney money1 = new HundredMoney();
money1.setShape(new Shape("纸币"));
// 原型模式 深克隆
HundredMoney money2 = (HundredMoney) money1.print();
System.out.println("money1 -> 引用对象地址:" + money1.getShape());
System.out.println("money2 -> 引用对象地址:" + money2.getShape());
System.out.println("引用对象地址比较:" + (money1.getShape() == money2.getShape()));
}
}
- 测试结果
money1 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@355da254
money2 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@12edcd21
引用对象地址比较:false
2.2.2. UML图例
3. 应用
// BeanUtils.copyProperties()
// JSON.parseObject()
// Guava copy 的工具类
// spring 中的 scope = "prototype" 就是通过加载 Spring 容器中的对象模板,复制出多实例的
// JDK 中 Arrays.copyOf()
4. 场景
- 类初始化消耗资源较多
- 创建对象的时候步骤繁琐(数据准备、访问权限等初始化)
- 构造函数复杂
- 循环体重创建大量对象
6. 优缺点
优点: 原型模式性能比直接new一个对象性能高;简化了创建过程
缺点: 必须配备克隆(或者可拷贝)方法;对克隆复杂对象或者对克隆出的对象进行复杂改造时,容易带来风险;浅克隆 和 深克隆 要运用得当