设计模式三十六计之原型模式(Prototype)
1. 设计思想
将一个对象作为指定的原型实例,并通过克隆此原型来创建新的对象
2. 演示案例
关于克隆,大家都知道克隆羊‘克隆羊多利’ ,本章节我们就以‘克隆羊多利’ 来演示原型模式
简而言之
原型模式就是克隆现有的对象来创建新的对象
百度百科:
原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
原型模式允许你创建现有对象的副本并更具实际需要进行修改,而不是从头开始创建新的对象并进行设置。
3. 代码示例
在Java中,一个对象只需要实现Cloneable接口,覆写clone方法,此clone方法名可以自定义,就可以完成原型模式的设计。
首先我们创建一个Sheep类并实现Cloneable接口:
public class Sheep implements Cloneable{
private String name;
public Sheep(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
/**
* 覆写clone方法
**/
@Override
public Sheep clone() throws CloneNotSupportedException{
return new Sheep(name); //此处是关键
}
}
然后我们可以通过如下的方式来克隆一个对象并进行修改:
public class TestPrototype{
public static void main(String[] args){
Sheep oldSheep = new Sheep("oldSheep");
System.out.println(oldSheep.getName());
//根据需要对oldSheep进行克隆和修改
Sheep cloneSheep = oldSheep.clone();
cloneSheep.setName("cloneSheep");
System.out.println(cloneSheep.getName());
}
}
输入内容:
oldSheep
cloneSheep
4. 适用范围
- 当系统独立于其他产品的创建、组合和表示方式的时候
- 当要在运行时指定实例化的类时,例如动态加载类
- 当需要避免重复创建结构相似的工厂类的时候
- 当一个类的实例可以有几个不同的状态组合时,创建相应数量的原型对象并进行克隆的方式比手动实例化类要简单得多。
- 当需要降低系统开销时。克隆对象的成本要比创建对象低很多
5. 浅克隆与深克隆
原型模式涉及到 浅克隆 与 深克隆 的概念 。首先我们通过代码来演示来说明什么是浅克隆。定义一个Sheep类实现Cloneable接口,并覆写clone方法,且在原来的代码基础上增加一个Color属性:
package com.ramostear.pattern.prototype;
/**
* @author ramostear
* @create-time 2019/1/4 0004-14:44
* @modify by :ramostear
* @info:[原型类:Sheep]
* @since:
*/
public class Sheep implements Cloneable{
private String name;
private Color color = new Color();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Sheep(String name) {
this.name = name;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep = (Sheep)super.clone();
return sheep;
}
}
说明:代码中增加了Color类的引用,Color类中什么都没有定义,只是一个空的类。
测试代码:
package com.ramostear.pattern.prototype;
/**
* @author ramostear
* @create-time 2019/1/4 0004-14:50
* @modify by :ramostear
* @info:[浅克隆测试代码]
* @since:
*/
public class TestPrototype {
public static void main(String[] args) throws CloneNotSupportedException{
Sheep sheep1 = new Sheep("sheep1");
Sheep sheep2 = (Sheep) sheep1.clone();
System.out.println("print hashcode ...");
System.out.println("sheep1`s hashcode:"+sheep1.hashCode());
System.out.println("sheep2`s hashcode:"+sheep2.hashCode());
System.out.println("print color ...");
System.out.println("sheep1`s color:"+sheep1.getColor().hashCode());
System.out.println("sheep2`s color:"+sheep2.getColor().hashCode());
}
}
控制台输出结果:
从输出结果可以看到,我们对sheep1进行了克隆,得到sheep2,此时的sheep2是一个全新的引用,但由于Sheep类中加入了另外的一个引用 Color,所以sheep1和sheep2对Color的引用还是同一个,输出的hashcode都为'356573597',证明Color的引用没有连带克隆,这就是浅克隆。
如何做到连同Color对象一起克隆而不是指向同一个引用?这就是接下来要讲的深克隆。
首先我们对Color类进行一些改造,让Color类同样实现Cloneable接口,并覆写clone方法。
package com.ramostear.pattern.prototype;
/**
* @author ramostear
* @create-time 2019/1/4 0004-15:08
* @modify by : ramostear
* @info:[Color类,实现Cloneable接口]
* @since:
*/
public class Color implements Cloneable{
private String color;
@Override
protected Object clone() throws CloneNotSupportedException {
Color color = (Color)super.clone();
return color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Color(String color) {
this.color = color;
}
public Color(){}
}
然后对Sheep的clone方法进行一些调整
package com.ramostear.pattern.prototype;
/**
* @author ramostear
* @create-time 2019/1/4 0004-14:44
* @modify by :ramostear
* @info:[原型类:Sheep]
* @since:
*/
public class Sheep implements Cloneable{
private String name;
private Color color = new Color();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Sheep(String name) {
this.name = name;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep = (Sheep)super.clone();
//增加了对color的设置
sheep.color = (Color) color.clone();
return sheep;
}
}
测试代码保持不变:
package com.ramostear.pattern.prototype;
/**
* @author ramostear
* @create-time 2019/1/4 0004-14:50
* @modify by :ramostear
* @info:[浅克隆测试代码]
* @since:
*/
public class TestPrototype {
public static void main(String[] args) throws CloneNotSupportedException{
Sheep sheep1 = new Sheep("sheep1");
Sheep sheep2 = (Sheep) sheep1.clone();
System.out.println("print hashcode ...");
System.out.println("sheep1`s hashcode:"+sheep1.hashCode());
System.out.println("sheep2`s hashcode:"+sheep2.hashCode());
System.out.println("print color ...");
System.out.println("sheep1`s color:"+sheep1.getColor().hashCode());
System.out.println("sheep2`s color:"+sheep2.getColor().hashCode());
}
}
输出结果:
从输出结果可以看到,我们对sheep1进行了克隆,得到sheep2,此时的sheep2是一个全新的引用,且sheep2的color也是一个全新的引用,至此,我们就实现了原型模式的深克隆。