设计模型之原型模式
1.原型模式
1.1 定义
原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
1.2 模式的结构
原型模式包含以下主要角色:
- 抽象原型类:规定了具体原型对象必须实现的接口。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
1.3 UML类图
1.4 问题由来
在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样简单。
1.5 实现思路
原型模式的克隆分为浅克隆和深克隆,Java 中的 Object 类提供了克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的克隆,这里的 Cloneable 接口就是抽象原型类
1.6 解决方案
/**
* @author tbb
* 多媒体附件
*/
public class Attachment implements Cloneable
{
private String img;
@Override
public String toString() {
return "Attachment [img=" + img + "]";
}
@Override
public Attachment clone() throws CloneNotSupportedException
{
return (Attachment)super.clone();
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
}
/**
* @author tbb
* 周报
*/
public class WeeklyReport implements Cloneable
{
private String title;
private String content;
private Attachment attachment;
@Override
public String toString() {
return "WeeklyReport [title=" + title + ", content=" + content + ", attachment=" + attachment + "]";
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
@Override
public WeeklyReport clone() throws CloneNotSupportedException
{
WeeklyReport cloneWeeklyReport = (WeeklyReport)super.clone();
Attachment cloneAttachment = cloneWeeklyReport.getAttachment().clone();
cloneWeeklyReport.setAttachment(cloneAttachment);
return cloneWeeklyReport;
}
}
public class Test
{
public static void main(String[] args)
{
WeeklyReport weeklyReport = new WeeklyReport();
weeklyReport.setTitle("tbb的周报");
weeklyReport.setContent("xxx");
Attachment attachment = new Attachment();
attachment.setImg("xx/yyy/aa.jpg");
weeklyReport.setAttachment(attachment);
//下个星期又要写周报了,这个时候直接拿上个星期的周报来改,就轻松很多了。
try
{
WeeklyReport xWeeklyReport = weeklyReport.clone();
System.out.println(xWeeklyReport);
System.out.println(weeklyReport);
weeklyReport.setTitle("12334");
weeklyReport.setContent("YYY");
//打印结果一样 初步证明clone深拷贝成功
/*
WeeklyReport [title=tbb的周报, content=xxx, attachment=Attachment [img=xx/yyy/aa.jpg]]
WeeklyReport [title=tbb的周报, content=xxx, attachment=Attachment [img=xx/yyy/aa.jpg]]
*/
// 修改原周报,复制的周报,没有跟着变化,证明使用clone深拷贝成功。
weeklyReport.getAttachment().setImg("zz/rr/bb.jpg");
System.out.println(xWeeklyReport);
System.out.println(weeklyReport);
/*
WeeklyReport [title=tbb的周报, content=xxx, attachment=Attachment [img=xx/yyy/aa.jpg]]
WeeklyReport [title=12334, content=YYY, attachment=Attachment [img=zz/rr/bb.jpg]]
*/
}
catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}