概述
什么是原型模式
原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的原型,这个原型是可定制的。原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据。
原型模式中的拷贝分为”浅拷贝”和”深拷贝”:
- 浅拷贝: 对原型对象中值类型的成员变量进行值的复制,对原型对象中原型对象中引用类型的成员变量只复制引用,不复制引用的对象。
- 深拷贝: 对原型对象中值类型的成员变量进行值的复制,对原型对象中引用类型的成员变量也进行引用对象的复制。
浅拷贝存在的问题
- 复制生成的实例中引用类型的成员变量与原型中的引用类型的成员变量使用的是同一引用,只要一方发生修改,另一方也就跟着改了。下面给出代码实例中就存在这样的问题,原型羊的生日发生修改,克隆羊的生日也会修改。
深拷贝如何实现
- 让已经实现Cloneable接口类中的属性也实现Clonable接口。
- 基本数据类型能够自动实现深克隆。
- 可以利用序列化和反序列化技术实现深克隆。
开发中的应用场景
原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
- Spring中的Bean的创建实际就是两种:单例模式和原型模式。(当然原型模式需要和工厂模式搭配起来)。
类图
代码
这里以克隆羊为例。
浅拷贝(克隆)
package com.match.prototype;
import java.io.Serializable;
import java.util.Date;
/**
* 浅复制
* @author Match
*
*/
public class Sheep implements Cloneable,Serializable
{
private static final long serialVersionUID = 1L;
private String sname;
private Date brithday;
public Sheep()
{
}
public Sheep(String sname, Date brithday)
{
this.sname = sname;
this.brithday = brithday;
}
@Override
protected Sheep clone() throws CloneNotSupportedException
{
Sheep sheep = (Sheep) super.clone();//直接调用object对象的clone()方法
return sheep;
}
public String getSname()
{
return sname;
}
public void setSname(String sname)
{
this.sname = sname;
}
public Date getBrithday()
{
return brithday;
}
public void setBrithday(Date brithday)
{
this.brithday = brithday;
}
}
package com.match.prototype;
import java.util.Date;
/**
* 测试原型模式(浅克隆)
* @author Match
*
*/
public class Client
{
public static void main(String[] args) throws Exception
{
Date date = new Date(12312321331L);
Sheep s1 = new Sheep("少利",date);//原型羊
Sheep s2 = s1.clone();//克隆羊
System.out.println("原型羊对象:"+s1);
System.out.println("原型羊的名字:"+s1.getSname());
System.out.println("原型羊的生日:"+s1.getBrithday());
System.out.println("-----------------------------—-------------------");
System.out.println("修改原型羊的生日:");
date.setTime(2343242423L);
System.out.println("修改后原型羊的生日:"+s1.getBrithday());
System.out.println("-----------------------------—-------------------");
s2.setSname("多利");
System.out.println("克隆羊对象:"+s2);
System.out.println("克隆羊的名字:"+s2.getSname());
System.out.println("克隆羊的生日:"+s2.getBrithday());
}
}
控制台输出:
原型羊对象:com.match.prototype.Sheep@15db9742
原型羊的名字:少利<br>
原型羊的生日:Sat May 23 20:05:21 CST 1970
-----------------------------—-------------------
修改原型羊的生日:<br>
修改后原型羊的生日:Wed Jan 28 10:54:02 CST 1970
-----------------------------—-------------------
克隆羊对象:com.match.prototype.Sheep@5c647e05
克隆羊的名字:多利<br>
克隆羊的生日:Wed Jan 28 10:54:02 CST 1970
深拷贝(克隆)
package com.match.prototype;
import java.util.Date;
/**
* 深复制
* @author Match
*
*/
public class Sheep2 implements Cloneable
{
private String sname;
private Date brithday;
public Sheep2()
{
}
public Sheep2(String sname, Date brithday)
{
this.sname = sname;
this.brithday = brithday;
}
@Override
protected Sheep2 clone() throws CloneNotSupportedException
{
Sheep2 s = (Sheep2) super.clone();//直接调用object对象的clone()方法
//添加如下代码实现深复制(deep clone)
s.brithday = (Date) brithday.clone();
return s;
}
public String getSname()
{
return sname;
}
public void setSname(String sname)
{
this.sname = sname;
}
public Date getBrithday()
{
return brithday;
}
public void setBrithday(Date brithday)
{
this.brithday = brithday;
}
}
package com.match.prototype;
import java.util.Date;
/**
* 测试原型模式(浅克隆)
* @author Match
*
*/
public class Client2
{
public static void main(String[] args) throws Exception
{
Date date = new Date(12312321331L);
Sheep2 s1 = new Sheep2("少利",date);
Sheep2 s2 = s1.clone();
System.out.println("原型羊对象:"+s1);
System.out.println("原型羊的名字:"+s1.getSname());
System.out.println("原型羊的生日:"+s1.getBrithday());
System.out.println("-----------------------------—-------------------");
System.out.println("修改原型羊的生日:");
date.setTime(2343242423L);
System.out.println("修改后原型羊的生日:"+s1.getBrithday());
System.out.println("-----------------------------—-------------------");
s2.setSname("多利");
System.out.println("克隆羊对象:"+s2);
System.out.println("克隆羊的名字:"+s2.getSname());
System.out.println("克隆羊的生日:"+s2.getBrithday());
}
}
控制台输出:
原型羊对象:com.match.prototype.Sheep2@15db9742
原型羊的名字:少利
原型羊的生日:Sat May 23 20:05:21 CST 1970
-----------------------------—-------------------
修改原型羊的生日:
修改后原型羊的生日:Wed Jan 28 10:54:02 CST 1970
-----------------------------—-------------------
克隆羊对象:com.match.prototype.Sheep2@5c647e05
克隆羊的名字:多利
克隆羊的生日:Sat May 23 20:05:21 CST 1970