定义:
所谓原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。 在原型模式中,所发动创建的对象通过请求原型对象来拷贝原型对象自己来实现创建过程,当然所发动创建的对象需要知道原型对象的类型。这里也就是说所发动创建的对象只需要知道原型对象的类型就可以获得更多的原型实例对象,至于这些原型对象时如何创建的根本不需要关心。
适用场景:
(1)类初始化消耗太多的资源
(2)new产生的一个对象需要非常繁琐的过程
(3)构造函数比较复杂
(4)循环体中产生大量的对象时候
优点:
(1)原型模式性能比直接new一个对象性能高
(2)简化创建过程
缺点:
(1)必须配备克隆方法
(2)对克隆复杂对象或者克隆出的对象进行复杂改造时候,容易引入风险
(3)深拷贝、浅拷贝要运用得当
讲到原型模式了,我们就不得不区分两个概念:深拷贝、浅拷贝。
浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。
深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值
浅拷贝案例如下:
代码中实现了对ProtoTypeProduct对象的克隆接口,对于克隆出来的对象pClone,pClone对象与p对象内容都是一样的,可以这样理解,克隆时候,内存中给克隆的对象分配了一组内存栈,栈中之存储比较浅的引用,对于成员变量,如果是常亮或者基本类型,克隆是直接克隆的值,如果是对象,只克隆对象的引用罢了。
public class PrototypeProduct implements Cloneable{
private String name;
private Date Date;
public PrototypeProduct(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return Date;
}
public void setDate(Date date) {
Date = date;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "PrototypeProduct{" +
"name='" + name + '\'' +
", Date=" + Date +
'}';
}
}
class Test{
public static void main(String[] args) {
try {
PrototypeProduct p = new PrototypeProduct();
p.setName("www");
p.setDate(new Date());
System.out.println(p);
PrototypeProduct pClone = (PrototypeProduct) p.clone();
System.out.println(pClone);
p.setName("qqq");
System.out.println(p);
System.out.println(pClone);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
对实现的接口方法clone重写,使得可以深克隆对象。
public class PrototypeProduct implements Cloneable{
private String name;
private Date Date;
public PrototypeProduct(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return Date;
}
public void setDate(Date date) {
Date = date;
}
@Override
protected Object clone() throws CloneNotSupportedException {
PrototypeProduct p = (PrototypeProduct) super.clone();
p.Date = (java.util.Date) p.Date.clone();
return p;
}
@Override
public String toString() {
return "PrototypeProduct{" +
"name='" + name + '\'' +
", Date=" + Date +
'}';
}
}
class Test{
public static void main(String[] args) {
try {
PrototypeProduct p = new PrototypeProduct();
p.setName("www");
p.setDate(new Date());
System.out.println(p);
PrototypeProduct pClone = (PrototypeProduct) p.clone();
System.out.println(pClone);
p.setName("qqq");
System.out.println(p);
System.out.println(pClone);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
最后要注意,克隆会破坏单例,单例在反射生成时候会得到不同的对象,所以请不要给单例实现克隆接口,或者可用接口的clone方法要重写返回单例的内部实例。