目录
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
以原型为模,克隆出所有属性均相同的对象
如克隆羊多利,记住这个例子,就不难理解原型模式了
使用场景
● 资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
● 性能和安全要求的场景
通过 new 产生一个对象需要非常繁琐的数据准备或访问权限。
● 一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用.
通用代码
public class PrototypeClass implements Cloneable{
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
}
return prototypeClass;
}
}
Cloneable & clone()
原型模式实际上就是实现 Cloneable 接口,重写 clone()方法。
public interface Cloneable {
}
Cloneable里没有方法就是一个标示,实现了这个接口就要重写clone方法
clone方法是顶级父类Object的方法
clone方法与与构造函数
clone方法会避开构造函数
从堆内存中以二进制流的方式进行拷贝,重新分配一个内存块
克隆羊例子
/**
* 原型羊🐑
*
* @author wmx
* @date 2019-08-20
*/
@Data
public class Sheep implements Cloneable{
private String name;
private String sex;
public Sheep() {
System.out.println("enter Constructor");
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep source = new Sheep();
source.setName("Jack");
source.setSex("公");
Sheep clone = (Sheep) source.clone();
clone.setName("Tom");
System.out.println("clone name : "+clone.getName()+",sex : "+clone.getSex());
}
}
输出:
enter Constructor
clone name : Tom,sex : 公
只进入了一次构造函数,证明了clone时没有进入构造函数
而且我们如果在clone对象生成后修改原型的属性,克隆的对象属性不变
如source.setSex("母");
Tom还是公的
浅拷贝 vs 深拷贝
概念:
浅拷贝: Object 类提供的方法 clone 只是拷贝本对象,其对象内部的数组、引用
对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝,其
他的原始类型比如 int、 long、 char、 string(当做是原始类型)等都会被拷贝。
注意: 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是
类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个
原始类型或不可变对象。
深拷贝: 对私有的类变量进行独立的拷贝
如: arrayList = (ArrayList<String>)this.arrayList.clone();
举个例子:
Sheep 类加个list记录羊的爱好
@Data
public class Sheep implements Cloneable{
private String name;
private String sex;
private List<String> hobbies;
public Sheep() {
System.out.println("enter Constructor");
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep source = new Sheep();
source.setName("Jack");
source.setSex("公");
source.setHobbies(Lists.newArrayList("吃草"));
Sheep clone = (Sheep) source.clone();
clone.setName("Tom");
List<String> hobbies = clone.getHobbies();
hobbies.add("睡觉");
source.setHobbies(hobbies);
System.out.println("clone name : "+clone.getName()+",sex : "+clone.getSex()+",hobbies"+clone.getHobbies());
}
}
修改了原型的list,然后克隆对象的list也被修改了
因此原型对象和克隆出的对象共用堆内的同一个list,没有对原型类中的类变量进行单独处理称为浅克隆
解决:在clone() 中对list也进行单独的处理
@Data
public class Sheep implements Cloneable{
private String name;
private String sex;
private ArrayList<String> hobbies = new ArrayList<>();
public Sheep() {
System.out.println("enter Constructor");
}
@Override
public Sheep clone(){
Sheep sheep = null;
try{
sheep = (Sheep) super.clone();
sheep.hobbies = (ArrayList<String>)this.hobbies.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return sheep;
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep source = new Sheep();
source.setName("Jack");
source.setSex("公");
source.setHobbies(Lists.newArrayList("吃草"));
Sheep clone = (Sheep) source.clone();
clone.setName("Tom");
ArrayList<String> hobbies = clone.getHobbies();
hobbies.add("睡觉");
//clone.setHobbies(hobbies);
System.out.println("clone name : "+clone.getName()+",sex : "+clone.getSex()+",hobbies : "+clone.getHobbies());
System.out.println("source name : "+source.getName()+",sex : "+source.getSex()+",hobbies : "+source.getHobbies());
}
}
输出:
enter Constructor
clone name : Tom,sex : 公,hobbies : [吃草, 睡觉]
source name : Jack,sex : 公,hobbies : [吃草]
说点什么
您将是第一位评论人!