Java 设计模式以虹猫蓝兔的故事讲解原型模式

 更新时间:2022年04月11日 08:58:12   作者:桃花键神  
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,今天通过本文给大家介绍下Java 原型设计模式,感兴趣的朋友一起看看吧

什么是原型模式

原型(Prototype)模式的定义如下: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。

优点

1、Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。

2、可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点

1、需要为每一个类都配置一个 clone 方法

2、clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。

3、当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

应用场景

在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样简单。

浅克隆

案例:克隆虹猫

浅克隆一个虹猫,外表特征一样,但是只有一个灵魂。

克隆虹猫身体受到伤害,本体虹猫不受影响。

克隆虹猫精神受到伤害,本体虹猫也受到同样的伤害。

代码实现

虹猫灵魂状态类

这里声明了虹猫的灵魂状态

public class Hong {
    //虹猫的灵魂状态
    private String lh;
    Hong(String lh) {
        this.lh = lh;
    }
    Hong() {
    }

    public String getLh() {
        return lh;
    }

    public void setLh(String lh) {
        this.lh = lh;
    }

}

虹猫个体类

实现了Cloneable 接口,并且有虹猫的身体状态和灵魂状态等属性。

public class Qian implements Cloneable {
    private String shou;
    private String jiao;
    private String yan;
    private Hong hong;

    Qian() {
    }

    Qian(String shou, String jiao, String yan, Hong hong) {
        this.hong = hong;
        this.shou = shou;
        this.jiao = jiao;
        this.yan = yan;
    }

    public Qian clone() throws CloneNotSupportedException {
        return (Qian) super.clone();
    }

    public String getShou() {
        return shou;
    }

    public void setShou(String shou) {
        this.shou = shou;
    }

    public String getJiao() {
        return jiao;
    }

    public void setJiao(String jiao) {
        this.jiao = jiao;
    }

    public String getYan() {
        return yan;
    }

    public void setYan(String yan) {
        this.yan = yan;
    }

    public Hong getHong() {
        return hong;
    }

    public void setHong(Hong hong) {
        this.hong = hong;
    }

}

测试类

这里测试一下浅克隆的效果:

浅克隆一个虹猫,外表特征一样,但是只有一个灵魂。

克隆虹猫身体受到伤害,本体虹猫不受影响。

克隆虹猫精神受到伤害,本体虹猫也受到同样的伤害。

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Qian qian = new Qian("两只手", "两只脚", "两只眼", new Hong("完整的灵魂"));
        Qian qian1 = qian.clone();
        System.out.printf("虹猫少侠本体的身体状态:%s,%s,%s,%s,", qian.getHong().getLh(), qian.getJiao(), qian.getShou(), qian.getYan());
        System.out.println();
        System.out.printf("虹猫少侠一号的身体状态:%s,%s,%s,%s,", qian1.getHong().getLh(), qian1.getJiao(), qian1.getShou(), qian1.getYan());

    }
}

克隆出来了一个虹猫一号,所有属性都一模一样

在这里插入图片描述

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Qian qian = new Qian("两只手", "两只脚", "两只眼", new Hong("完整的灵魂"));
        Qian qian1 = qian.clone();
        qian1.getHong().setLh("灵魂受到攻击");
        qian1.setJiao("断了一只脚");
        System.out.printf("虹猫少侠本体的身体状态:%s,%s,%s,%s,", qian.getHong().getLh(), qian.getJiao(), qian.getShou(), qian.getYan());
        System.out.println();
        System.out.printf("虹猫少侠一号的身体状态:%s,%s,%s,%s,", qian1.getHong().getLh(), qian1.getJiao(), qian1.getShou(), qian1.getYan());
    }
}

这里克隆虹猫的脚和灵魂都受到了伤害,本体虹猫的身体没有受到影响,但是灵魂却受到了伤害。

在这里插入图片描述

总结

一、为什么浅克隆中虹猫一号的脚受到了伤害,本体虹猫却没受到伤害?

二、为什么浅克隆中虹猫一号的灵魂受到了伤害,本体虹猫也受到了伤害?

因为创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。 两个虹猫的灵魂指向同一个内存地址,所以存储的是同一个灵魂。

深克隆

案例:克隆虹猫

深克隆一个虹猫,外表特征一样,都有独立灵魂。

克隆虹猫身体受到伤害,本体虹猫不受影响。

克隆虹猫精神受到伤害,本体虹猫也不受影响。

代码实现

虹猫灵魂状态类

这里声明了虹猫的灵魂状态,并且实现了Cloneable 接口,克隆一个虹猫灵魂

public class Hong implements Cloneable {
    //虹猫的灵魂状态
    private String lh;

    Hong(String lh) {
        this.lh = lh;
    }

    Hong() {
    }

    public Hong clone() throws CloneNotSupportedException {
        return (Hong) super.clone();
    }

    public String getLh() {
        return lh;
    }

    public void setLh(String lh) {
        this.lh = lh;
    }

}

虹猫个体类

重写了clone方法,在clone方法中调用了hong.clone()方法克隆了一个虹猫灵魂

public class Qian implements Cloneable {
    private String shou;
    private String jiao;
    private String yan;
    private Hong hong;

    Qian() {
    }

    Qian(String shou, String jiao, String yan, Hong hong) {
        this.hong = hong;
        this.shou = shou;
        this.jiao = jiao;
        this.yan = yan;
    }

    public Qian clone() throws CloneNotSupportedException {
        Qian qian = (Qian) super.clone();
        hong = hong.clone();
        return qian;

    }

    public String getShou() {
        return shou;
    }

    public void setShou(String shou) {
        this.shou = shou;
    }

    public String getJiao() {
        return jiao;
    }

    public void setJiao(String jiao) {
        this.jiao = jiao;
    }

    public String getYan() {
        return yan;
    }

    public void setYan(String yan) {
        this.yan = yan;
    }

    public Hong getHong() {
        return hong;
    }

    public void setHong(Hong hong) {
        this.hong = hong;
    }

}

测试类

这里测试一下浅克隆的效果:

深克隆一个虹猫,外表特征一样,都有独立灵魂。

克隆虹猫身体受到伤害,本体虹猫不受影响。

克隆虹猫精神受到伤害,本体虹猫也不受影响。

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Qian qian = new Qian("两只手", "两只脚", "两只眼", new Hong("完整的灵魂"));
        Qian qian1 = qian.clone();
        qian1.getHong().setLh("灵魂受到攻击");
        qian1.setJiao("断了一只脚");
        System.out.printf("虹猫少侠本体的身体状态:%s,%s,%s,%s,", qian.getHong().getLh(), qian.getJiao(), qian.getShou(), qian.getYan());
        System.out.println();
        System.out.printf("虹猫少侠一号的身体状态:%s,%s,%s,%s,", qian1.getHong().getLh(), qian1.getJiao(), qian1.getShou(), qian1.getYan());
    }
}

在这里插入图片描述

深克隆出的虹猫完全是个独立的个体,再也不用受限制了。

总结

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

到此这篇关于Java 设计模式以虹猫蓝兔的故事讲解原型模式的文章就介绍到这了,更多相关Java 原型模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springmvc DispatcherServlet原理及用法解析

    Springmvc DispatcherServlet原理及用法解析

    这篇文章主要介绍了Springmvc DispatcherServlet原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • springboot 整合druid及配置依赖

    springboot 整合druid及配置依赖

    这篇文章主要介绍了springboot 整合druid及jdbc 依赖、数据库依赖(mysql),druid 依赖的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 使用Jackson进行JSON生成与解析的新手指南

    使用Jackson进行JSON生成与解析的新手指南

    这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-04-04
  • java时区转换的理解及示例详解

    java时区转换的理解及示例详解

    这篇文章主要介绍了java时区转换的理解及示例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Spring框架构造注入操作实战案例

    Spring框架构造注入操作实战案例

    这篇文章主要介绍了Spring框架构造注入操作,结合具体实例形式分析了spring框架构造输入的相关定义与使用操作技巧,需要的朋友可以参考下
    2019-11-11
  • SpringBoot2.0整合tk.mybatis异常解决

    SpringBoot2.0整合tk.mybatis异常解决

    本文主要介绍了SpringBoot2.0整合tk.mybatis异常,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Spring Boot中@RequestParam参数的5种情况说明

    Spring Boot中@RequestParam参数的5种情况说明

    这篇文章主要介绍了Spring Boot中@RequestParam参数的5种情况说明,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • SpringMVC 使用JSR-303进行校验 @Valid示例

    SpringMVC 使用JSR-303进行校验 @Valid示例

    本篇文章主要介绍了SpringMVC 使用JSR-303进行校验 @Valid示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • SpringBoot整合sharding-jdbc 实现分库分表操作的示例代码

    SpringBoot整合sharding-jdbc 实现分库分表操作的示例代码

    在Spring Boot中使用ShardingSphere的Sharding-JDBC来实现数据库的分库分表是一个常见的需求,下面就拉具体介绍一下实现步骤,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • Spring如何通过@Lazy注解解决构造方法循环依赖问题

    Spring如何通过@Lazy注解解决构造方法循环依赖问题

    循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环,这篇文章主要给大家介绍了关于Spring如何通过@Lazy注解解决构造方法循环依赖问题的相关资料,需要的朋友可以参考下
    2023-03-03

最新评论