设计模式 原型模式

原型模式介绍

定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

原型模式主要解决的问题

如果创建对象的成本比较大,比如对象中的数据是经过复杂计算才能得到,或者需要从RPC接口或者数据库等比较慢的IO中获取,这种情况我们就可以使用原型模式,从其他已有的对象中进行拷贝,而不是每次都创建新对象,进行一些耗时的操作.

原型模式的优点

性能好,基于内存二进制流拷贝,比直接new 一个对象性能上提升许多。

可以使用深克隆方式保存对象的状态 ,使用原型模式将对象复制一份并将其状态保存起来,简化了创建过程

原型模式的缺点

实现原型模式需要自身实现克隆功能,增加对象设计的复杂性, 而且浅拷贝深拷贝问题会导致对象之间引用共享, 对于大量数据,克隆会消耗更多的资源, 对象暴露给外部方法,破坏封装性

浅克隆

浅克隆 通过 clone 创建一个与源对象完全相同的对象信息,对于基本值类型按值信息拷贝过去,对于对象类型采用会指向原有对象信息引用原有内存地址

实现了Cloneable接口,以指示Object.clone()方法,该方法对该类的实例进行逐个字段的复制是合法的。

在没有实现Cloneable接口的实例上调用Object的clonze方法将导致抛出CloneNotSupportedException异常。

按照约定,实现这个接口的类应该覆盖Object。使用公共方法克隆(受保护的)。有关重写此方法的详细信息,请参阅Object.clone()。

注意,这个接口不包含clone方法。因此,不可能仅仅因为对象实现了这个接口就克隆它。即使以反射方式调用clone方法,也不能保证它一定会成功。

如果不实现Cloneable接口,会抛出CloneNotSupportedException异常。

java 复制代码
public class Demo1Prototype implements Cloneable{
    private  String name;
    private String age;

    private  Demo2Prototype prototype;

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public Demo2Prototype getPrototype() {
        return prototype;
    }

    public void setPrototype(Demo2Prototype prototype) {
        this.prototype = prototype;
    }

    @Override
    public Demo1Prototype clone() throws CloneNotSupportedException {
        return (Demo1Prototype) super.clone();
    }
}

public class Demo2Prototype {
    private  String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Demo1Prototype demo1Prototype = new Demo1Prototype();
        demo1Prototype.setAge("13");
        demo1Prototype.setName("张三");
        Demo2Prototype demo2Prototype = new Demo2Prototype();
        demo2Prototype.setTest("test");
        demo1Prototype.setPrototype(demo2Prototype);
        System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest());
        Demo1Prototype clone = demo1Prototype.clone();
        clone.setAge("12");
        Demo2Prototype prototype = clone.getPrototype();
        prototype.setTest("test2");
        System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest());
        System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName()  + demo1Prototype.getPrototype().getTest());
    }
}

# 输出信息
PrototypeModel.Demo1Prototype@3b07d32913张三test
PrototypeModel.Demo1Prototype@4162934612张三test2
PrototypeModel.Demo1Prototype@3b07d32913张三test2
深克隆

上面引用对象重复的问题,我们只要对引用对象同样进行clone() 方法的再次调用就可以避免创建重复的对象信息

java 复制代码
public class Demo1Prototype implements Cloneable{
    private  String name;
    private String age;

    private  Demo2Prototype prototype;

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public Demo2Prototype getPrototype() {
        return prototype;
    }

    public void setPrototype(Demo2Prototype prototype) {
        this.prototype = prototype;
    }

    @Override
    public Demo1Prototype clone() throws CloneNotSupportedException {
        Demo1Prototype prototype1 = (Demo1Prototype) super.clone();
        Demo2Prototype clone = prototype1.getPrototype().clone();
        prototype1.setPrototype(clone);
        return prototype1;
    }
}

public class Demo2Prototype implements Cloneable{
    private  String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    @Override
    public Demo2Prototype clone() throws CloneNotSupportedException{
            return (Demo2Prototype) super.clone();
    }
}

# 输出信息
Demo1Prototype demo1Prototype = new Demo1Prototype();
demo1Prototype.setAge("13");
demo1Prototype.setName("张三");
Demo2Prototype demo2Prototype = new Demo2Prototype();
demo2Prototype.setTest("test");
demo1Prototype.setPrototype(demo2Prototype);
System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest());
Demo1Prototype clone = demo1Prototype.clone();
Demo2Prototype prototype = clone.getPrototype();
prototype.setTest("test2");
System.out.println(clone == demo1Prototype);
System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest());
System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName()  + demo1Prototype.getPrototype().getTest());

或者通过序列化的方式去实现

Serializable接口是启用其序列化功能的接口。实现java.io.Serializable 接口的类是可序列化的。没有实现此接口的类将不能使它们的任意状态被序列化或逆序列化。

序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

java 复制代码
import java.io.Serializable;

public class Demo1Prototype implements Serializable,Cloneable{
    private  String name;
    private String age;

    private  Demo2Prototype prototype;

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public Demo2Prototype getPrototype() {
        return prototype;
    }

    public void setPrototype(Demo2Prototype prototype) {
        this.prototype = prototype;
    }

    @Override
    public Demo1Prototype clone() throws CloneNotSupportedException {
        Demo1Prototype prototype1 = (Demo1Prototype) super.clone();
        return prototype1;
    }
}


import java.io.Serializable;

public class Demo2Prototype implements Serializable {
    private  String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Demo1Prototype demo1Prototype = new Demo1Prototype();
        demo1Prototype.setAge("13");
        demo1Prototype.setName("张三");
        Demo2Prototype demo2Prototype = new Demo2Prototype();
        demo2Prototype.setTest("test");
        demo1Prototype.setPrototype(demo2Prototype);
        System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName() + demo1Prototype.getPrototype().getTest());
        Demo1Prototype clone = null;
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
                ObjectOutputStream obs = new ObjectOutputStream(out)){
            obs.writeObject(demo1Prototype);
            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            clone = (Demo1Prototype)ois.readObject();
            ois.close();
        } catch (Exception ex){

        }
        Demo2Prototype prototype = clone.getPrototype();
        prototype.setTest("test2");
        System.out.println(clone.toString() + clone.getAge() + clone.getName() + prototype.getTest());
        System.out.println(demo1Prototype.toString() + demo1Prototype.getAge() + demo1Prototype.getName()  + demo1Prototype.getPrototype().getTest());
    }
}

# 执行结果
PrototypeModel.Demo1Prototype@3b07d32913张三test
PrototypeModel.Demo1Prototype@759ebb3d13张三test2
PrototypeModel.Demo1Prototype@3b07d32913张三test

浅拷贝只能在简单值之间使用, 为避免问题尽量采用深拷贝的方式

相关推荐
数据智能老司机3 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机4 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机4 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机4 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤4 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴1 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤1 天前
工厂模式
设计模式
幂简集成explinks2 天前
e签宝签署API更新实战:新增 signType 与 FDA 合规参数配置
后端·设计模式·开源