2020-07-23 原型模式

2020-08-05  本文已影响0人  竹blue

原型模式

原型模式通用写法

 是指通过拷贝原型实例来创建新的对象,具体来说是通过系统中已经存在的实例为原型,基于内存二进制流进行拷贝来创建新的对象;不调用构造函数。属于创建型模式。

  1. 因为是基于二进制流创建对象,相比基于构造函数创建对象,性能大大提高
  2. 可以通过来保存对象的中间状态,可用于数据的回滚操作。

 1. 需要类实现克隆方法。
 2. 克隆方法在类内部,对已有对象进行改造时违法开闭原则。
 3. 深度克隆需要编写较复杂的代码,如果当前对象存在多重嵌套,需要引用的类都支持深度克隆,实现比较麻烦,[注:可通过 JSON.parseObject(json,new TypeReference<Object>(){});
来规避。
]

 1. 类初始化消耗资源较多,如创建数据连接。
 2. 通过构造函数创建对象过程比较繁琐,如权限访问。
 3. 构造函数比较复杂。
 4. 循环创建大量对象。

 JDK源码中的ArrayList.clone()方法通过原型模式实现,通过实现Cloneable接口的clone()方法来实现浅克隆。
public class ArrayListextends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
   public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
}

浅clone

\color{red}{定义:}
 只是完整复制了值类型的数据,没有给引用对象赋值,使得引用对象仍指向原来对象的地址。
\color{red}{优点:}
  1. 规避了通过构造函数创建对象。
\color{red}{缺点:}
 1. 如果实例中存在引用对象,当拷贝对象的引用成员变量被修改时,原的对象该引用也被修改了
\color{red}{示例代码:}


public class ConcretePrototype {

    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 String toString() {
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

public class BeanUtils {

    public static Object copy(Object protorype) {
        Class clazz = protorype.getClass();
        Object returnValue = null;
        try {
            returnValue = clazz.newInstance();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                field.set(returnValue, field.get(protorype));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return returnValue;
    }
}

public class Client {
    public static void main(String[] args) {

        ConcretePrototype prototype = (ConcretePrototype)BeanUtils.copy(new ConcretePrototype());
        System.out.println(prototype);
    }
}

深clone

\color{red}{定义:}
 通过JSON或者序列化的方式(如:二进制流方式)使得引用对象得以赋值,[注意深度clone破坏了单例模式,二者是不能共存的。]
\color{red}{优点:}
 抽象工厂非常完美清晰地描述了产品族和产品等级结构之间的关系--即抽象工厂可以理解为工厂方法的集合。
\color{red}{示例代码:}

@Getter
@Setter
public class Person implements Serializable,Cloneable {
    /**
     * 年龄
     */
    private int age;
    /**
     * 姓名
     */
    private String name;
    /**
     * 爱好
     */
    private List hobbies;
}


@Setter
@Getter
public class Course implements Serializable {
    private String courseName;
}
@Getter
@Setter
public class Student extends Person {

    private Course course;

    private Timestamp birthday;

    /**
     * 深克隆
     *
     * @return
     */
    public Student deepClone(){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream outputStream = new ObjectOutputStream(bos);
            outputStream.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream inputStream = new ObjectInputStream(bis);

            Student result = (Student)inputStream.readObject();

            return result;
        }catch (Exception e){
            System.out.println("Failed to deep clone, reason is "+ e.getMessage());
            return null;
        }
    }
}

public class DeepCloneTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("小明");
        List<String> hobbies = new ArrayList<String>(1);
        hobbies.add("game");
        student.setHobbies(hobbies);
        student.setAge(10);
        student.setCourse(new Course());
        student.setBirthday(new Timestamp(System.currentTimeMillis()));


        Student deepClone = student.deepClone();
        System.err.println("深克隆:" + student.getCourse().equals(deepClone.getCourse()));
}

浅clone和深clone的区别

 1. 实现Cloneable接口的都是浅clone
 2. 通过序列化或转Json可实现深clone。

原型模式和单例模式的区别

原型模式的实例是不同的,单例模式创建出来的对象实例是相同的。

总结

 原型模式的核心是通过原型实例拷贝得到新的实例对象,适用于对象创建较为复杂的场景如构造函数较复杂(成员变量数量较大的情况),深度克隆相对浅克隆解决了引用对象赋值问题,但是增加了代码编写难度和内存占用(主要是因为破坏了单例模式)

上一篇下一篇

猜你喜欢

热点阅读