三、原型模式

一、什么是原型模式

  原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。原型模式包含以下主要角色。

  • 抽象原型类:规定了具体原型对象必须实现的接口。(Cloneable)
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。(Prototype)
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。(Main.class)

二、原型模式的实现

  深克隆与与浅克隆:Object类的clone方法只会克隆对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会克隆,这就是浅克隆。如果要实现深克隆,必须将原型模式中的数组、容器对象、引用对象等另行克隆。
  由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
1、创建Prototype的成员属性:


/*** @author FluffyCatkin* @version 1.0* @date 2021-03-31 0:12* @description Prototype的成员变量*/
public class Member implements Cloneable{private String position;public Member(String position) {this.position = position;}public void setPosition(String position) {this.position = position;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Member{" +"position='" + position + '\'' +'}';}
}

2、创建具体原型类Prototype:

import java.util.ArrayList;public class Prototype implements Cloneable{private String name ;private int age;private ArrayList<String> hobbies;private Member member;public Prototype(String name, int age, ArrayList<String> hobbies, Member member) {this.name = name;this.age = age;this.hobbies = hobbies;this.member = member;System.out.println("通过构造方法创建对象。。。。。。");}/*** 浅克隆*/@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}/*** 深克隆*/
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        Prototype clone = (Prototype) super.clone();
//        clone.setHobbies((ArrayList<String>) clone.getHobbies().clone());
//        clone.setMember((Member) clone.getMember().clone());
//        return clone;
//    }public void setName(String name){this.name = name;}public void setHobbies(ArrayList<String> hobbies) {this.hobbies = hobbies;}public ArrayList<String> getHobbies() {return hobbies;}public Member getMember() {return member;}public void setMember(Member member) {this.member = member;}@Overridepublic String toString() {return "Prototype{" +"name='" + name + '\'' +", age=" + age +", hobbies=" + hobbies +", member=" + member +'}';}
}

3、创建测试类(访问类):


import java.util.ArrayList;/*** 原型模式*  原型模式的定义与特点:*      原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,*      原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,*      如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。*      原型模式的结构与实现由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。*  模式的结构*      原型模式包含以下主要角色。*      抽象原型类:规定了具体原型对象必须实现的接口。   (Cloneable)*      具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。  (Prototype)*      访问类:使用具体原型类中的 clone() 方法来复制新的对象。  (Main.class)*/
public class Main {@Testpublic void prototypeTest() throws CloneNotSupportedException {Member initMember = new Member("c#");ArrayList<String> initHobbies = new ArrayList<>();initHobbies.add("play");Prototype prototype = new Prototype("张三",18,initHobbies,initMember);System.out.println("复制前");System.out.println("被克隆对象:"+prototype);Prototype prototype1 = (Prototype) prototype.clone();System.out.println("复制后");System.out.println("是否同一对象:"+(prototype==prototype1?"是":"否"));System.out.println("修改被克隆对象属性:");prototype.setName("李四");initHobbies.add("eat");initMember.setPosition("java");System.out.println("被克隆对象:"+prototype);System.out.println("克隆出的对象:"+prototype1);}}
  • 当把深克隆的实现方法注释,使用浅克隆的方法时

image.png

运行结果:


通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play, eat], member=Member{position='java'}}

  当修改被克隆对象hobbies与member属性的时候,克隆出来对象的hobbies与member属性也被修改,可见这两个属性都是同一对象引用,而String类型的name以及基础类型的age属性是不会被同时修改的,可见不是同一引用。浅克隆只复制对象的String类型属性以及一些基本类型属性,是不完全克隆。

  • 当把浅克隆的实现方法注释,使用深克隆的方法时

image.png

运行结果:


通过构造方法创建对象。。。。。。
复制前
被克隆对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}
复制后
是否同一对象:否
修改被克隆对象属性:
被克隆对象:Prototype{name='李四', age=18, hobbies=[play, eat], member=Member{position='java'}}
克隆出的对象:Prototype{name='张三', age=18, hobbies=[play], member=Member{position='c#'}}

  当修改被克隆对象name、age、hobbies以及member属性的时候,克隆出来对象的hobbies与member属性并未被修改,可见通过这种深克隆的方法,把所有的属性都创建一个新的内存对象,并使被克隆对象与克隆出的对象所有属性有不同的地址引用,深克隆的复制更加彻底。

  注意:上面代码在执行克隆的时候并未打印构造方法中的:“通过构造方法创建对象。。。。。。”,因此可见,使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。

三、应用场景

  原型模式通常适用于以下场景。

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
  • 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

四、优缺点分析

  原型模式的优点

  • Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

  原型模式的缺点

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

代码地址:https://gitee.com/fluffycatkin/JavaDesignModel.git

image.png

原文出处:
https://blog.csdn.net/zhengzhb/article/details/7393528
http://c.biancheng.net/view/1343.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/90440.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Quartus II安装下载驱动

Quartus II安装下载驱动 安装步骤&#xff1a; &#xff08;1&#xff09;安装完quartus后会自带USB-Blaster的驱动程序&#xff0c;因此不用再去网上下载。 &#xff08;2&#xff09;右键点脑左下角win&#xff0c;找到设备管理器并进入。 &#xff08;3&#xff09;找到…

达梦数据库管理用户和创建用户介绍

概述 本文主要对达梦数据库管理用户和创建用户进行介绍和总结。 1.管理用户介绍 1.1 达梦安全机制 任何数据库设计和使用都需要考虑安全机制&#xff0c;达梦数据库采用“三权分立”或“四权分立”的安全机制&#xff0c;将系统中所有的权限按照类型进行划分&#xff0c;为每…

Leetcode17电话号码的组合

思路&#xff1a;用字典的形式保存号码的映射&#xff0c;实际组合是前一个数字串的组合加上后面一个数字的所有可能组合 answer_dict{2:[a,b,c],3:[d,e,f],4:[g,h,i],5:[j,k,l],6:[m,n,o],7:[p,q,r,s],8:[t,u,v],9:[w,x,y,z]} class Solution:def letterCombinations(self, d…

七、MySQL(DML)如何往表中添加数据?

1、基础语法&#xff1a; &#xff08;1&#xff09;一对一添加数据&#xff1a; 一次只能添加一组数据&#xff0c;可以指定对应字段 insert into 表名 (字段名1,字段名2,……) values (数值1.数值2&#xff0c;……) &#xff08;2&#xff09;给全部字段添加数据&#…

异常的捕获和处理

目录 一、异常 1.异常概述 1.1认识异常 1.2Java异常体系结构 2.Java异常处理机制 2.1异常处理 2.2捕获异常 2.2.1使用try-catch捕获异常 2.2.2使用try-catch-finally处理异常 2.2.3使用多重catch处理异常 2.3抛出异常 2.3.1使用throws声明抛出异常 2.3.2使用throw…

etcd读写请求的执行过程

etcd读请求如何执行 首先&#xff0c;etcdctl 会对命令中的参数进行解析。在解析完请求中的参数后&#xff0c;etcdctl 会创建一个 clientv3 库对象通过gRPC API来访问 etcd server。对应流程一。 然后通过负载均衡算法选择一个etcd server节点&#xff0c;然后调用 etcd ser…

【计算机组成 课程笔记】2.1 设计自己的计算机

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 2 - 1 - 201-设计自己的计算机&#xff08;14‘24’‘&#xff09;_哔哩哔哩_bilibili 什么是指令系统体系结构&#xff1f;这个问题其实非常简单&#xff0c;但要想解释清楚也没有那么容易。我们还是从一个小故事…

机器学习技术(六)——有监督学习算法之线性回归算法实操

机器学习技术&#xff08;五&#xff09;——有监督学习之线性回归算法实操 引言&#xff1a; 机器学习监督算法是一种基于已有标记数据的学习方法&#xff0c;通过对已知输入和输出数据的学习&#xff0c;建立一个模型来预测新的输入数据的输出。这种算法模仿人类的学习过程&a…

Pycharm保存自定义布局

1.启用特定窗口 在View->Tool Windows下可以启用特定窗口&#xff0c;窗口标签会出现在左边&#xff08;图中红框处&#xff09;&#xff0c;下边或右边&#xff0c;可以拖动摆放位置 2.保存 在windows->layout下可以选择保存布局 1.图中第一个选项&#xff1a;选择或…

【Kafka】Kafka Stream简单使用

一、实时流式计算 1. 概念 一般流式计算会与批量计算相比较。在流式计算模型中&#xff0c;输入是持续的&#xff0c;可以认为在时间上是无界的&#xff0c;也就意味着&#xff0c;永远拿不到全量数据去做计算。同时&#xff0c;计算结果是持续输出的&#xff0c;也即计算结果…

计算机网络(速率、宽带、吞吐量、时延、发送时延)

速率&#xff1a; 最重要的一个性能指标。 指的是数据的传送速率&#xff0c;也称为数据率 (data rate) 或比特率 (bit rate)。 单位&#xff1a;bit/s&#xff0c;或 kbit/s、Mbit/s、 Gbit/s 等。 例如 4 1010 bit/s 的数据率就记为 40 Gbit/s。 速率往往是指额定速率或…

设计模式--代理模式(Proxy Pattern)

一、什么是代理模式&#xff08;Proxy Pattern&#xff09; 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许一个对象&#xff08;代理&#xff09;充当另一个对象&#xff08;真实对象&#xff09;的接口&#xff0c;以控制对该对象的…