孙悟空“拔毛变小猴”实现自我复制:
原型模式的定义:
注:
否定原型模式的误区:
原型模式的应用场景:
场景一:如果说我们的对象类型不是刚开始就能确定,而是这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的类型更容易。
场景二:我们可能在实际的项目中需要一个对象在某个状态下的副本,例如有的时候我们需要对比一个对象经过处理后的状态和处理前的状态是否发生过改变,可能我们就需要在执行某段处理之前,克隆这个对象此时状态的副本,然后等执行后的状态进行相应的对比
ORM数据更新:
场景三:当我们在处理一些对象比较简单,并且对象之间的区别很小,使用原型模式更合适。
例如七彩的颜色,我们只需要根据现有的一个颜色对象,克隆一个新的颜色对象,然后修改具体的颜色的值就可以满足要求,如果通过我们之前讲述的创建型工厂,抽象工厂模式等相对来说就引入新的依赖,并且复杂度也有所提高。
原型模式的结构:
原型模式包含以下3个角色:
抽象原型类是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口。
具体原型类实现具体的克隆方法,在克隆方法中返回自己的一个克隆对象。
让一个原型克隆自身,从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个对象,在通过调用该对象的克隆方法得到多个相同的对象。
Java实现:在Java中可以直接使用Object提供的clone方法实现对象的克隆。但需要注意的是,能够实现克隆的java类必须实现一个标识接口:Cloneable,标识这个Java类支持复制。如果一个类没有实现这个接口而调用了clone方法,java编译器将抛出一个CloneNotSupportedException异常。
代码如下:
package com.zyt.designpatterns.prototype;
public class PrototypeDemo implements Cloneable {
public Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
public static void main(String[] args) {
PrototypeDemo obj1 = new PrototypeDemo();
PrototypeDemo obj2 = (PrototypeDemo) obj1.clone();
}
}
java实现:在Java语言中,序列化(Serialization)就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,在从流里将其读出来,从而实现深克隆。实现深克隆的类需要实现Serializable标识接口。
Java语言原型模式的实现:
Java语言提供的clone方法将对象复制了一份并返回给调用者。一般而言,clone方法满足:
为了获取对象的一份拷贝,我们可以利用Object类的clone方法,具体步骤如下:
在使用某OA系统时,有些岗位的员工发现他们每周的工作都大同小异,因此在填写工作周报时很多内容都是重复的,为了提高工作周报的创建效率,大家迫切地希望有一种机制能够快速创建相同或者相似的周报,包括创建周报的附件。试使用原型模式对该OA系统中的工作周报创建模块进行改进。
结果与分析:
周报对象被成功复制,但是附件对象并没有复制,实现了浅克隆
1. 将周报类WeeklyLog和附件类Attachment标记为可序列化(Serializable)
[Serializable]
class WeeklyLog
{
private Attachment attachment;
……
}
[Serializable]
class Attachment
{
……
}
2. 修改周报类WeeklyLog的Clone()方法
//使用序列化方式实现深克隆
public WeeklyLog Clone()
{
WeeklyLog clone = null;
FileStream fs = new FileStream("Temp.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try {
formatter.Serialize(fs, this); //序列化
} catch (SerializationException e) {
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
} finally {
fs.Close();
}
FileStream fs1 = new FileStream("Temp.dat", FileMode.Open);
BinaryFormatter formatter1 = new BinaryFormatter();
try {
clone = (WeeklyLog)formatter1.Deserialize(fs1); //反序列化
} catch (SerializationException e) {
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
} finally {
fs1.Close();
}
return clone;
}
定义:原型管理器(Prototype Manager)将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得
结构:
下面代码实现一个颜色原型管理器:
抽象原型类MyColor:
/**
* 原型模式中,抽象原型类(这里使用的是接口)
* Created by yitian.z on 2016/3/21.
*/
public interface MyColor extends Cloneable {
public Object clone() throws CloneNotSupportedException;
public void display();
}
具体原型类Red:
/**
* 原型模式中,具体原型类A
* Created by yitian.z on 2016/3/21.
*/
public class Red implements MyColor {
public Object clone() {
Red red = null;
try {
red = (Red) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return red;
}
@Override
public void display() {
System.out.println("This is Red...");
}
}
具体原型类Blue:
/**
* 原型模式中,具体原型类B
* Created by yitian.z on 2016/3/21.
*/
public class Blue implements MyColor {
public Object clone() {
Blue blue = null;
try {
blue = (Blue) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return blue;
}
@Override
public void display() {
System.out.println("This is blue...");
}
}
原型管理器类PrototypeManager:
/**
* 原型管理器
* Created by yitian.z on 2016/3/21.
*/
public class PrototypeManager {
/**
* 私用成员
*/
private Hashtable hashtable = new Hashtable();
/**
* 默认构造方法
*/
public PrototypeManager() {
hashtable.put("red", new Red());
hashtable.put("blue", new Blue());
}
/**
* 添加颜色
* @param key colorName
* @param color MyColor
*/
public void addColor(String key, MyColor color) {
hashtable.put(key, color);
}
/**
* 获取颜色
* @param key colorName
* @return MyColor
* @throws CloneNotSupportedException
*/
public MyColor getColor(String key) throws CloneNotSupportedException {
return (MyColor) ((MyColor) hashtable.get(key)).clone();
}
}
客户端测试类Client:
/**
* Created by yitian.z on 2016/3/21.
*/
public class Client {
public static void main(String args[]) throws CloneNotSupportedException {
PrototypeManager prototypeManager = new PrototypeManager();
MyColor color1 = prototypeManager.getColor("red");
color1.display();
MyColor color2 = prototypeManager.getColor("blue");
color2.display();
System.out.println(color1 == color2);
}
}
模式优点
模式缺点
模式适用环境