原型模式
定义
是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
调用者不需要知道创建细节,不调用构建函数
属于创建型模式
原型模式的核心在于拷贝原型对象。以系统中已经存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需在经历耗时的对象初始化过程(不调用构造函数),性能提升许多。当对象的构建比较耗时时,可以利用当前系统中已经存在的对象作为原型,对其进行克隆,从而躲避初始化过程,使得新对象的创建时间大大较少。
适用场景
1. 类初始化小号资源较多
2. new产生一个对象需要非常繁琐的过程(数据准备,访问权限等)
3. 构造函数比较复杂
4. 循环体中生产大量对象
原型模式的通用写法
public interface IPrototype<T> {
T clone();
}
public class ConcretePrototype implements IPrototype{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
// ConcretePrototype concretePrototype = new ConcretePrototype();
// concretePrototype.setAge(this.age);
// concretePrototype.setName(this.name);
// return concretePrototype;
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
public class BeanUtils {
public static Object copy(Object prototype) {
Class clazz = prototype.getClass();
Object returnValue = null;
try {
returnValue = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
field.set(returnValue, field.get(prototype));
}
} catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
}
通过反射调用原型中的属性,赋值到新的对象中。
原型模式之浅克隆
Cloneable接口:cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常
public class ConcretePrototype implements Cloneable{
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
clone方法并不是把原型对象的引用赋值为克隆对象,而是在堆中重新开辟空间,将原型对象复制过去,将新的地址返回给克隆对象。但是对于原型对象中的引用对象,复制到克隆对象中的仍然是对象的引用,其对象不会发生改变。
原型模式之深克隆
深克隆的实现友两种方式:
1. 序列化
2. json
public class ConcretePrototype implements Cloneable, Serializable {
private int age;
private String name;
private List<String> hobbies;
public ConcretePrototype deepClone(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (ConcretePrototype) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
优点
- 性能优良,Java自带的原型模式是基于二进制流的拷贝,比直接new一个对象性能上提升很多
- 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存,简化了创建对象的过程,以便需要的时候使用(例如恢复到历史某一状态),可以辅助实现撤销操作
缺点
- 需要为每一个类配置一个克隆方法
- 克隆方法位于类的内部,当对已有的类进行改造的时候,需要修改代码,违反开闭原则。
- 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重嵌套应用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现比较麻烦。