原型模式:类提供一个克隆自己的方法,外界可以通过调用克隆的方法快速创建新的对象。
好处:
1.简化创建新对象的过程,提高效率
2.不用重新初始化对象,而是动态的获得对象运行时的状态(如:创建对象过程中属性值发生变化,克隆出来的就是变化后的值)
3.原型发生变化不用修改代码即可同步变化
缺点:
1.要为每个类配置克隆方法
2.对已有类改造时要修改源码,违背开闭原则
原型模式一,浅拷贝:
demo代码:
原型类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
//重写object的克隆方法
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return sheep;
}
}
客户端:
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom", 1, "白");
Sheep sheep1 = (Sheep) sheep.clone();
System.out.println(sheep==sheep1);
}
}
浅拷贝分析:
原型类实现Cloneable接口的clone()方法,通过clone方法实现自己的克隆。对于数据类型是基本数据类型的成员对象会进行值传递;对应数据类型是引用数据类型的成员变量如数组、类的对象等,会进行引用传递,即将成员变量的引用值复制一份给新对象
原型模式二,深拷贝:
demo:
原型的引用类:由于深拷贝特性,根据浅拷贝的实现方式选择实现Serializable、Cloneable接口:
@AllArgsConstructor
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serivalVersionUID = 1L;
private String cloneName;
private String cloneClass;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
原型类,如果用序列化方式的话实现Serializable即可,如果用重写clone()方法的话实现Cloneable接口,二者选其一,这里方便对比写一块了:
public class DeepPrototype implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepPrototype() {
super();
}
//方式1.重写clone()
@Override
protected Object clone() {
Object deep = null;
//对基本数据类型和String的克隆————克隆后得到deep对象
try {
deep = super.clone();
//对引用类型的属性进行单独处理————对deep的对象的deepCloneableTarget克隆,所以不能用this
DeepPrototype deepPrototype = (DeepPrototype) deep;
deepPrototype.deepCloneableTarget =
(DeepCloneableTarget) deepCloneableTarget.clone();
return deep;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
//方式2.序列化方式-推荐
public Object clone2() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
//当前这个对象一对象流的方式输出
oos.writeObject(this);
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepPrototype copyObj = (DeepPrototype) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
DeepPrototype d1 = new DeepPrototype();
d1.name = "123";
d1.deepCloneableTarget = new DeepCloneableTarget("345", "qwe");
// //1.重写clone()方式
DeepPrototype d2 = (DeepPrototype) d1.clone();
System.out.println("d1:" + d1.name + "\t d1:" + d1.hashCode());
System.out.println("d2:" + d2.name + "\t d1:" + d2.hashCode());
//2.序列化方式
DeepPrototype d3 = (DeepPrototype) d1.clone2();
System.out.println("d1:" + d1.name + "\t d1:" + d1.hashCode());
System.out.println("d3:" + d3.name + "\t d3:" + d3.hashCode());
}
}
深拷贝分析:
深拷贝复制原型对象所有基本数据类型的成员变量值;为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型变量所有引用的对象(即引用对象也引用其他对象的话就就复制引用对象引用的对象,一直到最底层)。
适用场景:当一个类需要大量创建对象时或对象的创建创建比较复杂时可以考虑原型模式
总结:原型模式相当于对大量相同对象做了一个抽象,对这些相同对象的管理交由原型类管理,当需要原型类对象们改变的时候不用改每个对象,只改原型类即可同步对象(***此处的改类不是破封装改原型类的代码,是通过get、set方法改属性值***)