天天看点

Java设计模式(五)原型模式原型模式

原型模式

定义

是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
调用者不需要知道创建细节,不调用构建函数
属于创建型模式
           

原型模式的核心在于拷贝原型对象。以系统中已经存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需在经历耗时的对象初始化过程(不调用构造函数),性能提升许多。当对象的构建比较耗时时,可以利用当前系统中已经存在的对象作为原型,对其进行克隆,从而躲避初始化过程,使得新对象的创建时间大大较少。

适用场景

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;
        }
    }
}
           

优点

  1. 性能优良,Java自带的原型模式是基于二进制流的拷贝,比直接new一个对象性能上提升很多
  2. 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存,简化了创建对象的过程,以便需要的时候使用(例如恢复到历史某一状态),可以辅助实现撤销操作

缺点

  1. 需要为每一个类配置一个克隆方法
  2. 克隆方法位于类的内部,当对已有的类进行改造的时候,需要修改代码,违反开闭原则。
  3. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重嵌套应用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现比较麻烦。