原型模式
- 简化创建对象过程,提高效率
- 不用重新初始化对象,而是动态的获取对象运行时的状态
- 需要为每一个类配备一个克隆方法,对已有的类进行改造时,需要修改其源码,违背了ocp原则,需要注意。
浅拷贝
- 数据类型为引用类型的的成员变量,比如数组,类对象等,浅拷贝只会进行引用传递,不会对其进行复制
- 默认使用clone()方法来实现
Cat类
public class Cat implements Cloneable{
private String name;
private int age;
private Cat friend;
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
public Cat getFriend() {
return friend;
}
public void setFriend(Cat friend) {
this.friend = friend;
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
测试类
/**
* 原型模式
*/
public class Prototype {
public static void main(String[] args) {
Cat cat = new Cat("珊珊",17);
cat.setFriend(new Cat("小王",20));
System.out.println("属性对象的hashcode: "+cat.getFriend().hashCode());
//复制
Cat cat1 = (Cat) cat.clone();
Cat cat2 = (Cat) cat.clone();
Cat cat3 = (Cat) cat.clone();
Cat cat4 = (Cat) cat.clone();
System.out.println("属性对象的hashcode: "+cat1.getFriend().hashCode());
System.out.println(cat.toString());
System.out.println("对象的hashcode:"+cat.hashCode());
System.out.println("对象的hashcode:"+cat2.hashCode());
System.out.println(cat1.toString());
System.out.println(cat2.toString());
}
}
输出结果
属性对象的hashcode: 460141958
属性对象的hashcode: 460141958
Cat{name='珊珊', age=17, friend=Cat{name='小王', age=20, friend=null}}
对象的hashcode:1163157884
对象的hashcode:1956725890
Cat{name='珊珊', age=17, friend=Cat{name='小王', age=20, friend=null}}
Cat{name='珊珊', age=17, friend=Cat{name='小王', age=20, friend=null}}
会发现friend对象属性所指向的是同一个对象,也就是对于这个属性并没有进行复制。
深拷贝
调用clone
Cat类
package com.rikka.prototype;
public class Cat implements Cloneable{
private String name;
private int age;
private Dog friend;
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Object clone() {
Object clone = null;
try {
clone = super.clone();
Cat cat = (Cat) clone;
cat.friend =(Dog) friend.clone();
return cat;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
Dog类
package com.rikka.prototype;
public class Dog implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类
package com.rikka.prototype;
/**
* 原型模式
*/
public class Prototype {
public static void main(String[] args) {
Cat cat = new Cat("珊珊",17);
cat.setFriend(new Dog("小王",20));
System.out.println("属性对象的hashcode: "+cat.getFriend().hashCode());
//复制
Cat cat1 = (Cat) cat.clone();
System.out.println("属性对象的hashcode: "+cat1.getFriend().hashCode());
System.out.println(cat.toString());
System.out.println("对象的hashcode:"+cat.hashCode());
System.out.println(cat1.toString());
System.out.println("对象的hashcode:"+cat1.hashCode());
}
}
此时Cat中的Dog对象属性也被复制(hashCode不同)
序列化(推荐使用)
Dog与Cat类都实现序列化接口(Serializable)
deepCopy()方法如下
:
public Object deepCopy(){
ByteArrayOutputStream byteArrayOutputStream = null;
ObjectOutputStream objectOutputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
ObjectInputStream objectInputStream = null;
try {
//序列化
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this); //以对象流的方式输出当前对象
//反序列化
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object object = objectInputStream.readObject();
return object;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
byteArrayOutputStream.close();
objectOutputStream.close();
byteArrayInputStream.close();
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
测试:
/**
* 原型模式
*/
public class Prototype {
public static void main(String[] args) {
Cat cat = new Cat("珊珊",17);
cat.setFriend(new Dog("小王",20));
System.out.println("属性对象的hashcode: "+cat.getFriend().hashCode());
Cat cat1 = (Cat) cat.deepCopy();
System.out.println("属性对象的hashcode: "+cat1.getFriend().hashCode());
System.out.println(cat.hashCode());
System.out.println(cat1.hashCode());
}
}
打印结果:
属性对象的hashcode: 460141958
属性对象的hashcode: 363771819
325040804
2065951873
spring 获取bean 对象时有用到原型模式
<bean id="" class="" scope="protype"/> //scope 使用原型模式创建bean对象