原型模式(Prototype Pattern)

  原型模式就是为了对象拷贝的,省掉了堆内存一系列的复杂流程。

  对象拷贝分为深拷贝和浅拷贝

  浅拷贝:将对象中的简单类型和String类型的值进行复制,引用类型复制的只是对象的引用地址

  深拷贝:所有的类型都是直接复制的值,包括引用对象;如果是引用对象,会新创建一个对象,并且引用地址改为该对象。

  原型模式的优点:

    1、根据客户端要求实现动态创建对象,客户端不需要知道对象的创建细节,便于代码的维护和发展

    2、使用原型模式创建对象比直接new一个对象在性能上要好得多,因为Object类的clone方法是一个本地方法,他直接操作内存中的二进制流,特别是复制大对象时,性能差别非常明显。

  使用原型模式时需要注意的点:

    1、使用原型模式复制对象不会调用类的构造方法

    2、在使用时要注意深拷贝和浅拷贝的问题

  浅拷贝代码示例:

package com.lcl.galaxy.design.pattern.prototype;

import java.io.Serializable;

public class Prototype implements Cloneable, Serializable {
    private static final long serialVersion = 1L;

    private String name;

    private int age;

    private Order order;

    public Prototype shallowClone() throws CloneNotSupportedException {
        Prototype prototype = (Prototype) super.clone();
        return prototype;
    }
}

  浅复制主要的点就是需要对象实现Cloneable接口,该接口没有方法,只是做一个标识,JVM虚拟机看到该标识后,就可以做对象的浅拷贝。至于具体哪个方法做对象复制,自己定义方法名即可,在方法中直接调用super的clone方法即可

  深拷贝代码示例:

package com.lcl.galaxy.design.pattern.prototype;


import java.io.*;

public class Prototype implements Cloneable, Serializable {
    private static final long serialVersion = 1L;

    private String name;

    private Order order;

    public void setName(String name) {
        this.name = name;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public String getName() {
        return name;
    }

    public Order getOrder() {
        return order;
    }public Prototype deepClone() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Prototype) ois.readObject();
    }
}

  深拷贝的代码主要是使用字节流来创建一个新的对象,那么无论是该对象本身还是该对象中的引用对象,都需要实现Serializable序列化接口。

  针对上述浅拷贝和深拷贝,测试代码如下:

package com.lcl.galaxy.design.pattern;

import com.alibaba.fastjson.JSON;
import com.lcl.galaxy.design.pattern.builder.Animal;
import com.lcl.galaxy.design.pattern.builder.AnimalBuilder;
import com.lcl.galaxy.design.pattern.prototype.Order;
import com.lcl.galaxy.design.pattern.prototype.Prototype;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@Slf4j
@SpringBootTest
public class PrototypeTest {

    @Test
    public void prototypeShallowCloneTest() throws CloneNotSupportedException {
        Prototype prototype = getPrototype();
        Prototype copyPrototype = prototype.shallowClone();
        print(prototype, copyPrototype);
    }

    @Test
    public void prototypeDeepCloneTest() throws IOException, ClassNotFoundException {
        Prototype prototype = getPrototype();
        Prototype copyPrototype = prototype.deepClone();
        print(prototype, copyPrototype);
    }


    private Prototype getPrototype(){
        Order order = new Order();
        order.setOrderId("1234");
        Prototype prototype = new Prototype();
        prototype.setOrder(order);
        prototype.setName("lcl");
        return prototype;
    }

    private void print(Prototype prototype, Prototype copyPrototype){
        log.info("prototype=================={}=================", prototype);
        log.info("copyPrototype=================={}=================", copyPrototype);
        log.info("prototype=================={}=================", JSON.toJSONString(prototype));
        log.info("copyPrototype=================={}=================", JSON.toJSONString(copyPrototype));
        log.info("prototype.getOrder()=================={}=================", prototype.getOrder());
        log.info("copyPrototype.getOrder()=================={}=================", copyPrototype.getOrder());
        log.info("prototype.equals(copyPrototype)=================={}=================", prototype.equals(copyPrototype));
        log.info("prototype.getName().equals(copyPrototype.getName())=================={}=================", prototype.getName().equals(copyPrototype.getName()));
        log.info("prototype.getOrder().equals(copyPrototype.getOrder())=================={}=================", prototype.getOrder().equals(copyPrototype.getOrder()));
        log.info("prototype.getOrder().getOrderId().equals(copyPrototype.getOrder().getOrderId())=================={}=================", prototype.getOrder().getOrderId().equals(copyPrototype.getOrder().getOrderId()));
    }

}

  最终的输出结构,虽然取到的值多一样,但是如果对比Prototype中的Order对象,浅拷贝和深拷贝则是两种结果:浅拷贝为true,即引用对象为同一个对象;深拷贝为false,即引用对象不是同一个对象。

原文地址:https://www.cnblogs.com/liconglong/p/14171657.html