创造型模式-原型模式(场景体验-》方案解决===代码图解)

news2025/1/12 1:48:54

创造型模式-原型模式

  • 创建重复对象-场景体验
  • 解决方案(原型模式)
  • 原型模式定义

创建重复对象-场景体验

  今天来一个大客户,他要求帮他下100个订单。每个订单除了用户ID,和用户名不同之外,其他个人信息完全相同。

订单类
public class Order{
	//id 主键,无实际意义
	private String id;
	//订单编号
	private String orderNo;
	//产品编码
	private String productNo;
	//产品名称
	private String productName;
	//产品类型
	private String productType;
	//订单购买数量
	private Integer num;
	//用户id
	private String userId;
	//用户名称
	private String userName;
	//用户电话号码
	private String tel;
	//用户住址
	private String address;
	//购买店铺,用于识别改订单是在哪一个店铺下的单。
	private Store store;
}
//商店类
public class Store{
	//店铺id
	private String id;
	//店铺名称
	private String name;
	//店铺负责人
	private String head;
	//店铺地址
	private Strign address;
}

制造数据:

public void copyOrder(){
	//专卖店
	Store store = new Store();
	store.setId("dp001");
	store.setName("地球村专卖店");
	store.setHead("村长");
	store.setAddress("东风东街001号");
	
	//第一个订单
	Order order = new Order();
	order.setId("111111");
	order.setOrderNo("dd001");
	order.setProductNo("cp001");
	order.setProductName("产品1");
	order.setProductType("工具类");
	order.setNum(50);
	order.setUserId("U001");
	order.setUserName("用户1");
	order.setTel("17660887362");
	order.setAddress("地球村-种花家");
	order.setStore(store);
	//第二个订单
	Order order1 = new Order();
	order.setId("111112");
	order.setOrderNo("dd002");
	order.setProductNo(order.getProductNo());
	order.setProductName(order.getProductName());
	order.setProductType(order.getProductType());
	order.setNum(order.getNum());
	order.setUserId("U002");
	order.setUserName("用户2");
	order.setTel(order.getTel());
	order.setAddress(order.getAddress());
	order.setStore(store);
	...
	还要100}

  上面的代码就是现状,当然也可以使用构造方法,但是过程都是一样的需要大量重复的代码。非常不美观。

解决方案(原型模式)

原型模式可以理解为:将一个完整对象的复制创建过程抽离成一个方法,使我们要创建一个相同对象的时候不需要再依次赋值。
模拟底层实现:

public class Order{
	//id 主键,无实际意义
	private String id;
	//订单编号
	private String orderNo;
	//产品编码
	private String productNo;
	//产品名称
	private String productName;
	//产品类型
	private String productType;
	//订单购买数量
	private Integer num;
	//用户id
	private String userId;
	//用户名称
	private String userName;
	//用户电话号码
	private String tel;
	//用户住址
	private String address;
	//购买店铺,用于识别改订单是在哪一个店铺下的单。
	private Store store;
	public Order clone(){
        Order order1 = new Order();
        order1.setId(this.id);
        order1.setOrderNo(this.orderNo);
        order1.setProductNo(this.productNo);
        order1.setProductName(this.productName);
        order1.setProductType(this.productType);
        order1.setNum(this.num);
        order1.setUserId(this.userId);
        order1.setUserName(this.userName);
        order1.setTel(this.tel);
        order1.setAddress(this.address);
        order1.setStore(this.store);
        return order1;
    }
	
}

我们使用的时候:


public void copyOrder(){
	//专卖店
	Store store = new Store();
	store.setId("dp001");
	store.setName("地球村专卖店");
	store.setHead("村长");
	store.setAddress("东风东街001号");

	//第一个订单
	Order order = new Order();
	order.setId("111111");
	order.setOrderNo("dd001");
	order.setProductNo("cp001");
	order.setProductName("产品1");
	order.setProductType("工具类");
	order.setNum(50);
	order.setUserId("U001");
	order.setUserName("用户1");
	order.setTel("17660887362");
	order.setAddress("地球村-种花家");
	order.setStore(store);
	//第二个订单
	Order order1 = order.clone();
	order.setId("111112");
	order.setOrderNo("dd002");
	order.setUserId("U002");
	order.setUserName("用户2");
	...
	之后的100个相同
}

通过上述方法使原本赋值操作的工作量大量减少,只需要关注自己个性化的赋值即可。
上面的clone方法是完全我自己写的用来模拟的,Java为我们提供了更好的实现,不需要我们去做上面无聊的赋值工作:
只需要Order类实现Cloneable接口,重写clone方法,在这个方法里面调用supper.clone()方法就好了。

public class Order{
	//id 主键,无实际意义
	private String id;
	//订单编号
	private String orderNo;
	//产品编码
	private String productNo;
	//产品名称
	private String productName;
	//产品类型
	private String productType;
	//订单购买数量
	private Integer num;
	//用户id
	private String userId;
	//用户名称
	private String userName;
	//用户电话号码
	private String tel;
	//用户住址
	private String address;
	//购买店铺,用于识别改订单是在哪一个店铺下的单。
	private Store store;
	@Override
    public Order clone(){
        Order order1 = new Order();
        try {
            order1 = (Order) super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return order1;
    }
}

  有兴趣的未来大佬们可以去看一下clone的源码,这里用的super.clone()是Object中的clone方法。这个方法是native的方法(本地方法)。Java中,用native关键字修饰的函数表明该方法的实现并不是在Java中去完成,而是由C/C++去完成,并被编译成了.dll,由Java去调用。方法的具体实现体在dll文件中,对于不同平台,其具体实现应该有所不同。用native修饰,即表示操作系统,需要提供此方法,Java本身需要使用。
  clone主要做的就是开创新的空间,将原对象的数据复制过去,再给返回引用。在Java里面所有的类如果重写clone方法就都是个性化的处理了。但是需要注意的是这个native的clone是浅拷贝。也就是在对象中还有对象的话,内部的对象clone之后还是原来的对象。

以咱们的代码举例:
  在Order类中有一个属性是Store的实例。在上面的clone执行之后如果改变clone之后的实例中的store属性,原本的order中的store属性也会改变。
在上面“copyOrder”代码的最后一行增加如下:

		System.out.println("order2"+order1);
        System.out.println("order:"+order);
        System.out.println("改变前order1:"+order1.getStore());
        System.out.println("改变前order:"+order.getStore());
        order1.getStore().setAddress("地球村-鹰酱家门头房");
        System.out.println("改变后order1:"+order1.getStore());
        System.out.println("改变前order:"+order.getStore());

在这里插入图片描述
可以看到,我们只改变了order1实例中store的address属性,但是order的对应属性也跟着一起变了。

如何解决上面的浅拷贝?

原型模式定义

  原型模式(Prototype Pattern)用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。

  这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

定义是引用自:菜鸟教程-原型模式

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DASCTF 2023 0X401七月暑期挑战赛RE题解

比赛期间没有什么时间,赛后做的题。 TCP 这题最难,耗时最久,好像做出来的人不多。 程序开始有个初始化随机数的过程,数据写入qword_5060开始的48个字节。 这里是主函数,连接到服务器以后,先接收32个字节…

c函数学习

函数的概念 函数是c语言的功能单位,实现一个功能可以封装一个函数来实现。定义函数的时候一切以功能为目的,根据功能去定义函数的参数和返回值 函数的分类 从定义角度分类:库函数(c库实现的),自定义函数&…

springboot集成

maven配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency><groupId>org.apache.commons</groupId><artifactId>…

小程序中vant-weapp时间选择使用方法

一、选择单个时间点&#xff1a; wxml&#xff1a; <van-celltitle"选择预约时间"value"{{ time }}"bind:click"onDisplay"/><van-calendarshow"{{ show }}"bind:close"onClose"bind:confirm"onConfirm"…

数学建模学习(3):综合评价类问题整体解析及分析步骤

一、评价类算法的简介 对物体进行评价&#xff0c;用具体的分值评价它们的优劣 选这两人其中之一当男朋友&#xff0c;你会选谁&#xff1f; 不同维度的权重会产生不同的结果 所以找到每个维度的权重是最核心的问题 0.25 二、评价前的数据处理 供应商ID 可靠性 指标2 指…

Redis应用(2)——Redis的项目应用(一):验证码 ---> UUID到雪花ID JMeter高并发测试 下载安装使用

目录 引出Redis的项目应用&#xff08;一&#xff09;&#xff1a;验证码1.整体流程2.雪花ID1&#xff09;UUID&#xff08;Universally Unique Identifier&#xff0c;通用唯一识别码&#xff09;2&#xff09;Twitter 的雪花算法&#xff08;SnowFlake&#xff09; 雪花ID优缺…

Jenkins常用管理功能配置 - 插件管理

Jenkins插件介绍 Jenkins是一个流行的开源持续集成/持续交付(CI/CD)工具&#xff0c;它有大量的插件来扩展其功能。这些插件可以用于构建、测试、部署和监控软件项目。下面是一些常用的Jenkins插件及其简单介绍和使用方法&#xff1a; 1. Git插件&#xff1a;允许Jenkins从Gi…

网络概念,《TCP/IP五层网络模型》与《数据的网络传输---“封装”与“分用”过程》

文章目录 概念协议协议分层TCP/IP五层网络模型数据的网络传输---“封装”与“分用”“封装”与“分用” 的过程 接收过程 概念 局域网&#xff1a;把一些设备通过交换机/路由器连接起来。 广域网&#xff1a;把更多的局域网也相互连接称为广域网。 交换机&#xff1a;交换机是…

采用桥接模式使虚拟机\笔记本\linux台式机互通

目录 一、环境&#xff1a;二、连接模式1. 桥接模式2. 主机共享模式3. NAT模式 三、配置1. 笔记本WIFI网络配置2. VM配置3.虚拟机配置3.1. 先看网络信息&#xff0c;确定修改ens333.2. 修改ens333.3. 重启网络 四、测试五、错误解决5.1 现象5.2 解决办法5.3 结果 一、环境&…

Spring中Bean的作用域和Spring生命周期

从前面的文章中我们看出Spring是用来存储和读取Bean的&#xff0c;因此Spring中Bean是最核心的资源&#xff0c;所以我们将对Bean进行深入的理解。 Bean的作用域 现在有一个公共的Bean&#xff0c;提供给了两个用户去使用&#xff0c;但是在使用过程中&#xff0c;用户一修改…

Android Studio 修改AVD模拟器文件默认存储路径

AndroidStudio默认的模拟器文件路径为&#xff1a;C:\Users\用户名\.android\avd路径&#xff0c;通常windows系统上&#xff0c;C盘不是太大&#xff0c;而avd文件却不小&#xff0c;通常几个GB&#xff0c;所以有必要将avd路径换到一个非系统盘。 更换方法如下&#xff1a;H…

LeetCode:6. N 字形变换

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340; 算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 题解目录 一、&#x1f331;[6. N 字形变换](https://leetcode.cn/problems/zigzag-conv…

5.3 Bootstrap 模态框(Modal)插件

文章目录 Bootstrap 模态框&#xff08;Modal&#xff09;插件用法选项方法事件 Bootstrap 模态框&#xff08;Modal&#xff09;插件 模态框&#xff08;Modal&#xff09;是覆盖在父窗体上的子窗体。通常&#xff0c;目的是显示来自一个单独的源的内容&#xff0c;可以在不离…

C语言:杨氏矩阵中查找某数(时间复杂度小于O(N))

题目&#xff1a; 有一个数字矩阵&#xff08;二维数组&#xff09;&#xff0c; 矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c; 请编写程序在这样的矩阵中查找某个数字是否存在&#xff0c; 要求&#xff1a;时间复杂度小于O(N)。 思路&#xff1…

Linux中docker的基本操作

文章目录 一、docker概述1.1 什么是docker1.2 Docker与虚拟机的特性区别1.3 容器在内核中支持2种重要技术1.4 docker的核心概念 二、安装docker三、Docker 镜像操作四、Docker 容器操作 一、docker概述 1.1 什么是docker 是一个开源的应用容器引擎&#xff0c;基于go语言开发…

Spring Web MVC 详解(1)

目录 一、介绍 MVC 二、Spring MVC 的三个基本功能 1.1 连接功能 1.2 Spring MVC 的创建和使用 1.3 RequestMappig 介绍 1.4 Spring MVC 实现用户和 Spring 程序的连接 1.5 GetMapping 和 PostMaping 注解 1.6 Get 和 Post请求注解的多种写法 2.1 获取请求中参数的功…

Redis的内存回收与内存淘汰策略

对于redis这样的内存型数据库而言&#xff0c;如何删除已过期的数据以及如何在内存满时回收内存是一项很重要的工作。 常见的redis内存回收的工作主要分为两个方面&#xff1a; 清理过期的key在内存不足时回收到足够的内存用以存储新的key 清理过期的key 我们很少在redis中…

直接插入排序、希尔排序、直接选择排序、堆排序、冒泡排序——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是数据结构与算法啦&#xff0c;是排序&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入七大排序的世界吧&#xff01;&#xff01;&#xff01; 排序的概念及其运用 排序的概念 排序&#xff1a;所谓排序…

算法提高-动态规划-斜率优化DP

斜率优化DP AcWing 300. 任务安排1AcWing 301. 任务安排2AcWing 302. 任务安排3AcWing 303. 运输小猫 AcWing 300. 任务安排1 #include <iostream> #include <cstring>typedef long long LL;using namespace std;const int N 5e3 10;int st[N], sc[N]; LL f[N];…

全志F1C200S嵌入式驱动开发(基于usb otg的spi-nor镜像烧入)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 前面既然已经搞定了spi-nor驱动,那么下一步考虑的就是怎么从spi-nor flash上面加载uboot、kernel和rootfs。目前spi-nor就是一块白片,上面肯定什么都没有,那么这个时候,我们要做…