一、原型模式概述
原型模式是一种特殊的创建型模式,它通过复制一个已有对象来获取更多相同或者相似的对象。原型模式可以提高相同类型对象的创建效率,简化创建过程。
二、原型模式克隆机制
- 浅克隆(Shallow Clone)
浅克隆:如果原型对象的成员变量是值类型(如 int、double、byte、boolean、char等基本数据类型),将复制一份给克隆对象;如果原型对象的成员变量是引用类型(如类、接口、数组等复杂数据类型),则将引用对象的地址复制一份给克隆对象,也就是说克隆对象的成员变量指向相同的内存地址。简单来说,在浅克隆中,当原型对象被复制时只是复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
- 深克隆(Deep Clone)
深克隆:无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
三、原型模式实现
- 通用实现
public abstract class Prototype {
public abstract Prototype clone();
}
class ConcretePrototype extends Prototype{
private String attr;
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
@Override
public Prototype clone() {
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAttr(this.attr);
return prototype;
}
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAttr("simple");
Prototype clone = prototype.clone();
System.out.println(prototype==clone);//false
}
}
- Java中的clone()方法和Cloneable接口(示例为浅克隆)
class ConcretePrototype implements Cloneable{
private String attr;
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAttr("simple");
ConcretePrototype clone = (ConcretePrototype)prototype.clone();
System.out.println(prototype==clone);//false
System.out.println("prototype:"+prototype+" hashcode:"+ prototype.hashCode());
System.out.println("clone:"+clone+" hashcode:"+ clone.hashCode());
}
}
- 深克隆的实现(深克隆实现方式有多种,示例代码为推荐实现方法)
/**
* 周报
*/
public class WeeklyLog implements Serializable, Cloneable {
private Attachment attachment;
private String name;
private String date;
private String content;
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
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 WeeklyLog clone() {
Object object = null;
try {
object = super.clone();//调用Object clone方法
return (WeeklyLog) object;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
/**
* 使用序列化技术实现深克隆
*/
public WeeklyLog deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (WeeklyLog) ois.readObject();
}
}
/**
* 附件
*/
class Attachment implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void download() {
System.out.println("下载附件:文件名为:" + name);
}
}
class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Attachment attachment = new Attachment();
attachment.setName("附件一");
WeeklyLog weeklyLog = new WeeklyLog();
weeklyLog.setName("测试");
weeklyLog.setAttachment(attachment);
//深克隆
WeeklyLog clone = weeklyLog.deepClone();
System.out.println(weeklyLog == clone);//false
System.out.println(weeklyLog.getAttachment() == clone.getAttachment());//false
//浅克隆
WeeklyLog clone1 = weeklyLog.clone();
System.out.println(weeklyLog == clone1);//false
System.out.println(weeklyLog.getAttachment() == clone1.getAttachment());//true
}
}
四、使用场景
- 订单的复制(商品对象)。
- 周报的复制(附件对象)。
- spring中原型bean的创建。