java设计模式-原型模式

什么是原型(Prototype)模式

  • 原型模式是一个创建型模式
  • 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象;即对象的拷贝;

优缺点

  • 优点:在初始化信息不发生变化的情况下,使用克隆,即隐藏了对象的创建细节,对性能有提升;
  • 缺点:每个类必须准备一个clone方法,且clone方法需要对类的功能进行考虑;

简单的UML图

原型模式UML简图

原型模式的应用场景(相对来说)

  • new 构造对象需要非常繁琐的数据准备时,可以使用原型模式,进行对象的快速复制;
  • 多方使用当前对象,且都会对当前对象进行修改,调用方又相互独立,各自修改的值不想影响到其他调用方时,可以考虑通过原型模式复制多个对象(深拷贝)供调用方使用;
  • 创建对象时,需要保留原型对象的数据时;
  • 注意,通过实现Cloneable接口的原型模式在调用clone()方法并不一定都比new构造对象快,只有new构造对象较为耗时或成本较高时考虑使用;所以使用前需要仔细考虑,并进行相应的测试;
  • 原型模式利用对象拷贝的形式实现,需要注意对象的浅拷贝、深拷贝的不同

浅拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。

clone实现浅拷贝

public class ShallowClone implements Cloneable {

    private boolean flag;

    private Integer index;

    private String str;

    private ShallowPeople shallowPeople;


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public ShallowPeople getShallowPeople() {
        return shallowPeople;
    }

    public void setShallowPeople(ShallowPeople shallowPeople) {
        this.shallowPeople = shallowPeople;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "ShallowClone{" +
                "flag=" + flag +
                ", index=" + index +
                ", str='" + str + '\'' +
                ", shallowPeople=" + shallowPeople +
                '}';
    }
}
public class ShallowPeople {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}
public class CloneMain {

    private static final Log LOGGER = LogFactory.getLog(CloneMain.class);

    public static void main(String [] args) throws Exception {
        shallowClone();
        System.out.println("-----------------------------------------");
        depthClone();
        System.out.println("-----------------------------------------");
        depthCloneSerializable();
    }

    /**
     * 浅拷贝测试
     */
    private static void shallowClone() {
        ShallowClone shallowClone = new ShallowClone();
        shallowClone.setFlag(true);
        shallowClone.setIndex(1);
        ShallowPeople shallowPeople = new ShallowPeople();
        shallowPeople.setAge(12);
        shallowPeople.setName("xiaoming");
        shallowClone.setShallowPeople(shallowPeople);
        shallowClone.setStr("123");

        System.out.println("原:" + shallowClone);
        /**
         * 这里可以看出,修改clone出来的对象里的ShallowPeople 信息,影响到了原对象
         * 这是因为浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
         */
        ShallowClone shallowClone1 = null;
        try {
            shallowClone1 = (ShallowClone) shallowClone.clone();
        } catch (CloneNotSupportedException e) {
            LOGGER.error("shallow clone error : {}", e);
            return;
        }
        shallowClone1.getShallowPeople().setName("heihei");
        shallowClone1.setStr("456");
        System.out.println("新:" + shallowClone1);
        System.out.println("原1:" + shallowClone);
    }


    /**
     * 深拷贝测试
     */
    private static void depthClone() {
        DepthClone depthClone = new DepthClone();
        depthClone.setFlag(false);
        depthClone.setIndex(2);
        DepthPeople depthPeople = new DepthPeople();
        depthPeople.setAge(11);
        depthPeople.setName("xiaoqiang");
        depthClone.setDepthPeople(depthPeople);

        System.out.println("原:" + depthClone);

        /**
         * 这里可以看出,修改clone出来的对象里的ShallowPeople 信息,对原对象无影响
         * 这是因为深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
         *
         * 通过例子看出,深拷贝则是对浅拷贝的递归
         */
        DepthClone depthClone1 = null;
        try {
            depthClone1 = (DepthClone) depthClone.clone();
        } catch (CloneNotSupportedException e) {
            LOGGER.error("depth clone error : {}", e);
            return;
        }
        depthClone1.getDepthPeople().setName("heihei");
        System.out.println("新:" + depthClone1);
        System.out.println("原1:" + depthClone);
    }

    private static void depthCloneSerializable() {
        DepthCloneSerializable depthCloneSerializable = new DepthCloneSerializable();
        depthCloneSerializable.setFlag(true);
        depthCloneSerializable.setIndex(3);
        People people = new People();
        people.setAge(20);
        people.setName("xiaoliu");
        depthCloneSerializable.setPeople(people);

        System.out.println("原:" + depthCloneSerializable);
        DepthCloneSerializable depthCloneSerializable1 = null;
        try {
            depthCloneSerializable1 = (DepthCloneSerializable) depthCloneSerializable.deepClone();
        } catch (Exception e) {
            System.err.println("depthCloneSerializable error : " + e.getMessage());

            LOGGER.error("depthCloneSerializable error : {}", e);
            return;
        }
        depthCloneSerializable1.getPeople().setName("heihei");
        System.out.println("新:" + depthCloneSerializable1);
        System.out.println("原1:" + depthCloneSerializable);
    }
}

我们可以通过输出结果看出,浅拷贝生成的对象中的ShallowPeople信息修改,影响到了原型对象,原因是因为浅拷贝是仅拷贝对象本身,不拷贝对象内包含的引用指向的对象,且保留引用;
浅拷贝结果

深拷贝

深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象

clone实现深拷贝

public class DepthClone implements Cloneable {

    private boolean flag;

    private Integer index;

    private DepthPeople depthPeople;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DepthClone depthClone = null;
        try {
            depthClone = (DepthClone) super.clone();
            depthClone.setDepthPeople((DepthPeople) depthClone.getDepthPeople().clone());
        } catch (CloneNotSupportedException e) {
            throw e;
        }

        return depthClone;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public DepthPeople getDepthPeople() {
        return depthPeople;
    }

    public void setDepthPeople(DepthPeople depthPeople) {
        this.depthPeople = depthPeople;
    }

    @Override
    public String toString() {
        return "DepthClone{" +
                "flag=" + flag +
                ", index=" + index +
                ", depthPeople=" + depthPeople +
                '}';
    }
}

public class DepthPeople implements Cloneable {

    private String name;

    private Integer age;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "DepthPeople{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

我们可以通过输出结果看出,深拷贝并没有对原型对象有任何影响;
深拷贝结果
通过以上实现可以看出,通过clone实现深拷贝,其实就是对原型对象的所有子引用对象进行再次clone;类似对浅拷贝的一种递归实现。

通过序列化的方式实现深拷贝

public class DepthCloneSerializable implements Serializable {

    private boolean flag;

    private Integer index;

    private People people;

    public Object deepClone() throws IOException, SecurityException, ClassNotFoundException {
        // 写出去

        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bo);
        oos.writeObject(this);
        // 读回来
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bi);
        return ois.readObject();
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public People getPeople() {
        return people;
    }

    public void setPeople(People people) {
        this.people = people;
    }

    @Override
    public String toString() {
        return "DepthCloneSerializable{" +
                "flag=" + flag +
                ", index=" + index +
                ", people=" + people +
                '}';
    }

}
public class People implements Serializable {
    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "DepthPeople{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

拷贝结果
序列化方式的深拷贝结果

copyProperties工具及比较

引用:copyProperties工具及比较
引用:Orika介绍
Orkia

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值