设计模式之创建型设计模式-原型模式

1. 模式简介

原型实例指定创建对象的种类,通过克隆这些原型创建新的对象。调用者不需要指定对象的创建细节,不通过调用构造函数创建对象。属于创建型设计模式

2. 示例代码

2.1. 浅克隆

2.1.1. 代码实现

  • 原型接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* <p>
* 钱
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:53
*/
public interface Money {
/**
* 打印
*
* @return {@link Money}
*/
Money print();
}
  • 具体实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* <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;
}
}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* <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()));
}
}
  • 测试结果
1
2
3
money1 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@1d44bcfa
money2 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@1d44bcfa
引用对象地址比较:true

2.1.2. UML图例

原型模式-浅克隆UML图例

2.2. 深克隆

深克隆一定需要实现 Serializable 接口

2.2.1. 代码实现

  • 原型接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* <p>
* 钱
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-14 15:53
*/
public interface Money {
/**
* 打印
*
* @return {@link Money}
*/
Money print();
}
  • 具体实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* <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();
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* <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()));
}
}
  • 测试结果
1
2
3
money1 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@355da254
money2 -> 引用对象地址:com.xkcoding.design.pattern.creational.prototype.Shape@12edcd21
引用对象地址比较:false

2.2.2. UML图例

原型模式-深克隆UML图例

3. 应用

1
2
3
4
5
6
7
8
9
// BeanUtils.copyProperties()

// JSON.parseObject()

// Guava copy 的工具类

// spring 中的 scope = "prototype" 就是通过加载 Spring 容器中的对象模板,复制出多实例的

// JDK 中 Arrays.copyOf()

4. 场景

  • 类初始化消耗资源较多
  • 创建对象的时候步骤繁琐(数据准备、访问权限等初始化)
  • 构造函数复杂
  • 循环体重创建大量对象

6. 优缺点

优点: 原型模式性能比直接new一个对象性能高;简化了创建过程

缺点: 必须配备克隆(或者可拷贝)方法;对克隆复杂对象或者对克隆出的对象进行复杂改造时,容易带来风险;浅克隆深克隆 要运用得当

7. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/creational/prototype

-------------本文结束  感谢您的阅读-------------
xkcoding wechat
欢迎来我的公众号「xkcoding小凯扣丁」逛逛
o(╯□╰)o 赞助一杯咖啡 ~~