一.定义与类型
1.定义:指原型实例指定创建对象的种类,并且通过拷贝这些原型对象创建新的对象
不需要知道任何创建的细节,不调用构造函数
2.类型:创建型
二.适用场景
1.类初始化消耗较多的资源
2.new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
3.构造函数比较复杂
4.循环体中生产大量对象时
三.优点
1.原型模式性能比直接new一个对象性能高
2.简化创建过程
四.缺点
1.必须配备克隆方法
2.对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
3.深拷贝、浅拷贝要运用得当
五.扩展
1.深克隆
2.浅克隆
六.代码
package com.caomingyu.autotest.prototype;
import java.util.Date;
public class Pig implements Cloneable {
private String name;
private Date birthday;
public Pig(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Pig{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}' + super.toString();
}
}
package com.caomingyu.autotest.prototype;
import java.util.Date;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Date birthday = new Date(0L);
Pig pig1 = new Pig("佩奇",birthday);
Pig pig2 = (Pig) pig1.clone();
System.out.println(pig1);
System.out.println(pig2);
pig1.getBirthday().setTime(666666666666L);
System.out.println(pig1);
System.out.println(pig2);
}
}
打印结果
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.caomingyu.autotest.prototype.Pig@2c7b84de
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.caomingyu.autotest.prototype.Pig@3fee733d
Pig{name='佩奇', birthday=Sat Feb 16 09:11:06 CST 1991}com.caomingyu.autotest.prototype.Pig@2c7b84de
Pig{name='佩奇', birthday=Sat Feb 16 09:11:06 CST 1991}com.caomingyu.autotest.prototype.Pig@3fee733d
可以看到修改了pig1的生日,pig2也被修改了,原因是因为默认的clone是浅拷贝,没有拷贝类里面的引用类,两个pig里面的date是同一个对象,所以我们需要修改Pig.java的重写方法clone,修改代码如下:
@Override
protected Object clone() throws CloneNotSupportedException {
Pig pig = (Pig) super.clone();
pig.birthday = (Date) pig.birthday.clone();
return pig;
}
七.如何防止原型模式破坏单例模式
1.单例类不要去实现Cloneable接口
2.实现Cloneable接口的clone方法,但是里面不要用默认的super.clone(),而是用单例里面的getInstance获取单例的方法