原型模型
原型模型是一种创建型(为了合理创建对象而设计的模式)的设计模型,,用来处理代码中,复制对象的操作。Spring 中原型 bean 的创建,就是原型模式的应用
不使用原型模型设计模式:
Pet pet=new Pet("小虎","22");//一个普通对象
//企图复制10个pet,通过get例子中的属性,调用构造方法
Pet pet1=new Pet(pet.getName(),pet.getAge());
Pet pet2=new Pet(pet.getName(),pet.getAge());
Pet pet3=new Pet(pet.getName(),pet.getAge());
Pet pet4=new Pet(pet.getName(),pet.getAge());
Pet pet5=new Pet(pet.getName(),pet.getAge());
Pet pet6=new Pet(pet.getName(),pet.getAge());
Pet pet7=new Pet(pet.getName(),pet.getAge());
Pet pet8=new Pet(pet.getName(),pet.getAge());
可以发现多次get属性,一旦属性多了,就会出现很多重复的代码,同时也会造成混乱。
使用原型模式
1.原型类实现克隆接口(就是相当于开启复制的功能)
```java
public class Pet implements Cloneable {
private String name;
private String age;
2.重写一个clone()方法,这是Object类的方法(所有类都直接或者间接继承Object类)
@Override
protected Object clone(){
Pet p=null;
try{
p=(Pet) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
3.直接调用clone()克隆方法
Pet pet=new Pet("小虎","22");//一个普通对象
//直接调用Pet的clone方法
Pet pet1=(Pet) pet.clone();
Pet pet2=(Pet) pet.clone();
Pet pet3=(Pet) pet.clone();
Pet pet4=(Pet) pet.clone();
Pet pet5=(Pet) pet.clone();
Pet pet6=(Pet) pet.clone();
Pet pet7=(Pet) pet.clone();
Pet pet8=(Pet) pet.clone();
Pet pet9=(Pet) pet.clone();
- 创建新的对象比较复杂的时候,可以利用原型模式简化对象的创建,同时也能提高效率
- 不用重新初始化对象,而是动态地获得对象运行时状态
- 如果原始对象发生变化(增加或者删除了属性),其他地克隆对象也会相应地发生变化,无需修改代码
- 在实现深拷贝的时候,可能会需要比较复制的代码
- 缺点:需要为每个类配备一个克隆方法,这对全新的类影响不大,但是对于旧的类,需要修改代码,违反了ocp原则。
深浅拷贝讲解
深浅拷贝:拷贝的深浅针对于引用类型(不包含基本数据类型和String)拷贝而来的对象的对象字段是独立的,例如,一个Person对象的pet宠物属性(宠物也是一个对象),如果以Person A为原型拷贝出了Person B,那么深拷贝的情况下,A.petB.pet(为false),也就是两个宠物对象的地址是不一样的,而浅拷贝的情况下,A.petB.pet(为true,也就是A宠物和B的宠物实际上是同一个宠物,修改其中一个宠物就会影响到另一个宠物。
浅拷贝示例:
Pet pet=new Pet("小狗","11");
Person p1=new Person("小菜",pet);//小菜,小狗
Person p2= (Person) p1.clone();//小菜,小狗
p2.getPet().setName("小虎");
Person p3= (Person) p1.clone();//小菜,小虎
System.out.println("p1-------"+p1.getPet());//Pet{name='小虎', age='11'}
System.out.println("p2------"+p2.getPet());//Pet{name='小虎', age='11'}
System.out.println("p3-------"+p3.getPet());//Pet{name='小虎', age='11'}
System.out.println("p1-------"+p1.getPet().hashCode());//356573597
System.out.println("p2-------"+p2.getPet().hashCode());//356573597
System.out.println("p3--------"+p3.getPet().hashCode());//356573597
可以发现p2的宠物进行了修改,影响到了p1的宠物。
深拷贝示例
Pet pet=new Pet("小狗","22");
Person p1=new Person("小擦",pet);
Person p2=(Person) p1.clone();
p2.getPet().setName("大笨蛋");
Person p3=(Person) p1.clone();
System.out.println(p1);//小狗 22
System.out.println(p2);//大笨蛋 22
System.out.println(p3);//小狗 22
可以发现修改了p2 并没有影响到p1
深拷贝的实现方法2:
通过对象序列化的方式,对象序列化是一种持久化对象的技术。先将源对象进行序列化,然后再从另一个位置对序列化的对象进行反序列化,最后间接完成复制。
protected Object clone() throws CloneNotSupportedException {
Object person=null;
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
try {
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);//直接调用对象流来序列该对象,序列化到数组输出流中
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
//创建一个数组输入流,从上面的数组输出流中的数据
try {
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);//用对象输入流承载数组输入流的数据
person=(Person)objectInputStream.readObject();//直接对象输入流之中获取对象
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
finally {
try {
byteArrayOutputStream.close();
byteArrayInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return person;
}
以上是重写的clone方法
测试
Pet pet=new Pet("小狗","22");
Person p1=new Person("小擦",pet);
Person p2=(Person) p1.clone();
p2.getPet().setName("大笨蛋");
Person p3=(Person) p1.clone();
System.out.println(p1);//小狗 22
System.out.println(p2);//大笨蛋 22
System.out.println(p3);//小狗 22
System.out.println(p1.getPet().hashCode());//692404036
System.out.println(p2.getPet().hashCode());//867859325
System.out.println(p3.getPet().hashCode());//553976328
可以发现篇p2修改宠物对象并不影响 p1对象的宠物。而且3个对象的宠物对象的hashcode都不一样!!