不懂使用为学过,说出用途,绘制结构为了解,不会灵活使用基本等于没学。
前言
西游记中孙悟空拔毛出分身的故事大家都知道,孙悟空根据了自己的形象创建了分身,克隆出了一个和自己几乎一模一样的身外身,设计模式中也有一个类似的模式,叫做克隆模式,它是属于创建型模式的一种模式
什么是原型模式 Prototype Pattern
使用原型实例指定创建对象的种类,并且通过克隆这些原型创建新的对象,这就是克隆模式
原型模式的优点
(1)、当创建新的对象相对而言比较麻烦时,我们可以使用原型模式简化对象的创建过程,通过复制一个已有的实例可以提高新实例的创建效率
(2)、原型模式的拓展性是很好的。由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体类写入配置文件中,增加或者减少具体原型类对原有系统都没有任何影响
(3)、原型模式提供了简化的创建模式,对比工厂模式中常常需要有一个与产品等级结构相同的工厂等级结构,而原型模式不需要这样,原型模式是通过自己本身就封装好的原型类的克隆方法实现的,无须专门的工厂类创建产品。
(4)、可以使用深克隆模式来保存对象的状态,辅助实现撤销的操作。
原型模式的劣势
(1)、实现原型模式需要给每一个类配置一个克隆的方法,且该方法位于类的内部,当对已有的类修改时会违背开闭原则
(2)、实现深克隆需要实现较为复杂的代码,而且对象之间存在多重关系的嵌套引用时,为了实现深克隆每一个类都需要支持深克隆,实现起来会比较麻烦
原型模式的使用场景
(1)、创建的成本比较大(比如初始化需要比较长的时间,占用太多的CPU或者网络资源)
(2)、如果系统需要保存对象的状态,而对象状态变化很小,或者对象本身占用内存比较少
(3)、避免使用分层次的工厂类来创建分层次的对象。
浅克隆和深克隆的区别
原型模式又有两种,浅克隆只克隆对象本身,而对象内包含的对象不会克隆,只会引用同一个位置的包含的对象
深克隆会将对象本身和被对象包含的对象都会克隆一份。
原型模式的具体实现
(1)、浅克隆(只需要实现Cloneable接口)
public class WeeklyLog implements Cloneable {
private String name;
private String date;
private String context;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public WeeklyLog clone() {
Object obj = null;
try {
obj = super.clone();
return (WeeklyLog) obj;
} catch (CloneNotSupportedException e) {
System.out.println("不支持复制");
e.printStackTrace();
return null;
}
}
}
(2)、深克隆(实现 Serializable 接口)
// Cloneable潜克隆所使用的java接口
//深克隆使用序列化接口
public class WeekLog implements Serializable {
private String name;
private String date;
private String content;
private Attachment attachment;
//使用序列号实现深克隆
public WeekLog deepLone()throws Exception{
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (WeekLog) ois.readObject();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
}
import java.io.Serializable;
//实现序列号接口,做到深克隆
public class Attachment implements Serializable {
private String name;
public void download(){
System.out.println("下载附件,名字为"+name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}