设计模式 原型模式

原型模式介绍

定义: 原型模式(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

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

相关推荐
无奇不有 不置可否4 小时前
Java中的设计模式
java·开发语言·设计模式
YGGP11 小时前
【创造型模式】简单工厂模式
设计模式
努力学习的明11 小时前
Spring Bean 生命周期中设计模式的应用与解析
java·spring·设计模式·生命周期
77tian14 小时前
设计模式的原理及深入解析
java·开发语言·单例模式·设计模式·代理模式·享元模式·原型模式
wu~9701 天前
手撕四种常用设计模式(工厂,策略,代理,单例)
java·单例模式·设计模式·代理模式·抽象工厂模式·策略模式
敲代码的 蜡笔小新2 天前
【行为型之访问者模式】游戏开发实战——Unity灵活数据操作与跨系统交互的架构秘诀
unity·设计模式·c#·访问者模式
软考真题app2 天前
软件设计师考试结构型设计模式考点全解析
设计模式·软件设计师·结构型设计模式·考试考点
xiaolin03332 天前
【设计模式】- 行为型模式1
设计模式·状态模式·责任链模式·策略模式·命令模式·模板方法模式·行为型模式
沐土Arvin2 天前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
bao_lanlan2 天前
兰亭妙微:用系统化思维重构智能座舱 UI 体验
ui·设计模式·信息可视化·人机交互·交互·ux·外观模式