原型模式介绍
原型模式采用对象克隆的方式来生成新的重复对象。在实际的软件开发中,可能存在需要多次创建重复或者类似对象的情况,此时原型模式提供了一种相对创建新对象更高效更快捷的一种创建方式。
适用场景
- 新对象的创建初始化需要消耗大量的资源
- 一个对象会频繁的被使用,且彼此的使用需要相对独立
- 优化程序的性能,节约系统资源(浅拷贝)
原型结构
原型模式主要由三部分构成
1. 抽象原型类
抽象原型类需要提供给具体原型类的对应接口方法,需要指明自我克隆的方法,是所有具体原型类的父类
2. 具体原型类
实现具体的类接口方法及克隆方法
3. 请求客户端
调用具体原型类来克隆对象
克隆方法
1. 浅克隆
浅克隆一般情况是指直接实现JAVA Object类提供的Cloneable接口,通过clone函数克隆对象。
浅克隆会复制新的原型对象与新的值对象,但是对于引用类型成员对象,只是复制引用地址而非对象本身,仍然指向与原型相同的地址
2.深克隆
深克隆则主要使用JAVA的Serializable接口,通过对对象进行序列化方式来实现。
深克隆会克隆包括引用对象在内的克隆对象的全部属性
浅克隆案例
假设目前我们有一个WORD模板的抽象类,下面有两个不同的模板,我们经常需要复用这两个模板去撰写自己的内容,这里为了方便会简化具体的模型。
抽象原型类
@Data
//抽象模板类
public abstract class TemplatePrototype implements Cloneable{
String Text=" ";
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public abstract void Download();
}
在抽象原型内部实现clone函数,同时模板提供Text内容
具体模板类
模板A
@Data
public class TemplateA extends TemplatePrototype{
String title=" ";
@Override
public void Download() {
System.out.println("下载模板A");
}
}
相对于原模板增加标题内容
模板B
@Data
public class TemplateB extends TemplatePrototype{
String summarize;
@Override
public void Download() {
System.out.println("下载模板B");
}
}
相较原模板增加总结内容
测试
@Test
public void cloneTest() throws CloneNotSupportedException, IOException, ClassNotFoundException {
TemplateA templateA = new TemplateA();
TemplateA clone = (TemplateA) templateA.clone();
TemplateB templateB = new TemplateB();
TemplateB clone1 = (TemplateB) templateB.clone();
System.out.println("克隆前后的引用对象是否相同");
System.out.println(clone.getText()==templateA.getText());
System.out.println(clone.getTitle()==templateA.getTitle());
clone.Download();
clone1.Download();
}
测试结果
克隆前后的引用对象是否相同
true
true
下载模板A
下载模板B
可以看到使用浅拷贝的时候引用对象的实际地址是相同的
深拷贝案例
抽象原型类
@Data
//抽象模板类
public abstract class TemplatePrototype1 implements Serializable {
String Text=" ";
public Object deepClone() throws IOException,ClassNotFoundException, OptionalDataException {
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis =new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois =new ObjectInputStream(bis);
return (ois.readObject());
}
public abstract void Download();
}
这里使用流来完成对象的深拷贝
具体模板类
@Data
public class TemplateB1 extends TemplatePrototype1{
String summarize=" ";
@Override
public void Download() {
System.out.println("下载模板B");
}
}
测试
@Test
public void deepCloneTest() throws CloneNotSupportedException, IOException, ClassNotFoundException {
TemplateB1 templateB1 = new TemplateB1();
TemplateB1 DeepTemplateB1 = (TemplateB1) templateB1.deepClone();
System.out.println("克隆前后的引用对象是否相同");
System.out.println(DeepTemplateB1.getText()==templateB1.getText());
System.out.println(DeepTemplateB1.getSummarize()==templateB1.getSummarize());
}
测试结果
克隆前后的引用对象是否相同
false
false
可以看到在深拷贝中引用的对象的实际地址也发生了变化,与浅拷贝不同
总结
- 原型模式的优点在于其可以快速的创建大量相同或相似的复杂对象,提高开发速度的同时优化系统性能
- 原型模式的缺点在于需要一开始规划好原型类的设计,原型类的后期改动会异常麻烦
- 原型模式的适用场景多体现在需要频繁的应用一个相同或相似状态的对象或者对象本身的创建成本过于大。一个对象本身的状态在软件中越固定,越适合原型模式