重构数据-Change Value to Reference将实值对象改为引用对象三
重构数据-Change Value to Reference将实值对象改为引用对象三
1.将实值对象改为引用对象
1.1.实值对象和引用对象区别
下面通过客户Customer和订单Order两个对象介绍下它们的区别
值对象:当一个客户Customer下了多个订单Order后,每个订单类都将创建一个客户对象,即使多个订单属于同一个客户,但每个Order对象还是拥有各自的Customer对象。所以对于多个订单Order来说没办法共享同一个客户的信息。
引用对象:同 一客户拥有多份不同定单,代表这些定单的所有Order对象就可以共享同一个Customer对象以及对象中的所有属性信息。
1.2.使用场景
当A和B两个对象之间是1对多关系时,就可以将值对象转为引用对象。实现的方法有很多中,例如单例模式就是其中的一种。
例如上面的客户和订单关系就是1对多关系,多个订单共享同一个客户对象。
1.3.如何做
- 使用Replace Constructor with Factory Method (304)。
- 编译,测试。
- 决定由什么对象负责提供访问新对象的途径。
- 可能是一个静态字典或一个注册表对象。
- 你也可以使用多个对象作为新对象的访问点。
- 决定这些引用对象应该预先创建好,或是应该动态创建。
- 如果这些引用对象是预先创建好的,而你必须从内存中将它们读取出来,那么就得确保它们在被需要的时候能够被及时加载。
- 修改工厂函数,令它返回引用对象。
- 如果对象是预先创建好的,你就需要考虑:万一有人索求一个其实并不存在的对象,要如何处理错误?
- 你可能希望对工厂函数使用Rename Method (273),使其传达这样的信息:它返回的是一个既存对象。
- 编译,测试。
1.4.示例
在Replace Data Value with Object 一节中,我留下了一个重构后的程序,本节范例就从它开始。我们有下列的Customer class:
class Customer {public Customer (String name) {_name = name;}public String getName() {return _name;}private final String _name;}
它被 Order class使用
class Order...public Order (String customerName) {_customer = new Customer(customerName);}public void setCustomer(String customerName) {_customer = new Customer(customerName);}public String getCustomerName() {return _customer.getName();}private Customer _customer;
此外,还有一些代码也会使用Customer对象
private static int numberOfOrdersFor(Collection orders, String customer) {int result = 0;Iterator iter = orders.iterator();while (iter.hasNext()) {Order each = (Order) iter.next();if (each.getCustomerName().equals(customer)) result++;}return result;}
到目前为止,Customer对象还是value object。就算多份定单属于同一客户,但每个Order对象还是拥有各自的Customer对象。
我希望改变这一现状,使得同 一客户拥有多份不同定单,代表这些定单的所有Order对象就可以共享同一个Customer对象。本例中这就意味:每一个客户名称只该对应一个Customer对象。
首先我使用 Replace Constructor with Factory Method。这样,我就可以控制Customer对象的创建过程,这在以后会是非常重要的。我在Customer class中定义这个factory method:
class Customer {
// 创建一个实例化Customer对象方法,该方法称为工厂方法public static Customer create (String name) {return new Customer(name);}
然后我把「对构造函数的调用」替换成「对factory method的调用」:
class Order {public Order (String customer) {// 调用工厂方法创建Customer对象_customer = Customer.create(customer);}
然后我再把构造函数声明为private:
class Customer {private Customer (String name) {_name = name;}
现在,我必须决定如何访问Customer对象。
我比较喜欢通过另一个对象(例如Order class中的一个值域)来访问它。但是本例并没有这样一个明显的值域可用于访问Customer对象。
在这种情况下,我通常会创建一个注册(登录)对象,作为访问点。为了简化我们的例子,我把Customer对象保存在Customer class的一个static值域中,让Customer class作为访问点:
private static Dictionary _instances = new Hashtable();
然后我得决定:应该在接到请求时创建新的Customer对象,还是应该预先将它们创建好。这里我选择后者。
在应用程序的启动代码(start-up code)中,我先把需要使用的Customer对象加载妥当。这些对象可能来自数据库,也可能来自文件。为求简单起见,我在代码中明确生成这些对象。反正以后我总是可以使用 Substitute Algorithm 来改变它们的创建方式。
class Customer...static void loadCustomers() {new Customer ("Lemon Car Hire").store();new Customer ("Associated Coffee Machines").store();new Customer ("Bilston Gasworks").store();}private void store() {_instances.put(this.getName(), this);}
现在,我要修改factory method,让它返回预先创建好的Customer对象:
public static Customer create (String name) {return (Customer) _instances.get(name);}
由于create()总是返回既有的Customer对象,所以我应该使用Rename Method 修改这个factory method的名称,以便强调(说明)这一点。
class Customer...public static Customer getNamed (String name) {return (Customer) _instances.get(name);}
相关文章:
重构数据-Change Value to Reference将实值对象改为引用对象三
重构数据-Change Value to Reference将实值对象改为引用对象三 1.将实值对象改为引用对象 1.1.实值对象和引用对象区别 下面通过客户Customer和订单Order两个对象介绍下它们的区别 值对象:当一个客户Customer下了多个订单Order后,每个订单类都将创建一…...
计算机网络——通信专业面试问题学习笔记
文章目录1、计算机网络这门课学了什么?目录里有多少章?2、Internet的概念与发展史3、什么是交换?三种交换方式4、OSI的七层协议, TCP/IP的四层协议, 五层协议5、WAN 、LAN 、MAN、PAN这些能分的清楚吗?全称分别都是什么࿱…...
代码随想录算法训练营第三十天 | 332.重新安排行程 51. N皇后 37. 解数独 总结
打卡第30天,回溯算法第二刷。 今日任务 332.重新安排行程51.N皇后37.解数独总结 332.重新安排行程 给你一份航线列表 tickets ,其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从…...
Windows权限提升—MySQL数据库提权
Windows权限提升—MySQL数据库提权1. 前言2. 数据库提权介绍2.1. 常见数据库端口2.2. MySQL数据库提权条件2.3. MySQL数据库提权类型3. MySQL中UDF提权3.1. UDF提权介绍3.2. UDF提权思路3.3. UDF提权步骤3.3.1. 获取外连数据库3.3.1.1. 外连数据库3.3.1.2. 连接数据库3.3.1.3. …...
使用旧电脑玩Linux
今天给大家讲讲使用旧电脑玩Linux,大家应该都知道旧电脑的硬件一般比较落后,特别是一些非常老的电脑,目前还在使用的是机械硬盘,如是要跑windows可想而知,但是Linux系统对硬件性能的要求可比windows低的多了࿰…...
Linux安装EMQX(简洁版)
安装目录 mkdir /opt/emqx && cd /opt/emqx 安装包下载 yum -y install wget && wget https://www.emqx.com/zh/downloads/broker/5.0.20/emqx-5.0.20-el7-amd64.tar.gz 注意:https://www.emqx.com/zh/downloads/broker获取下载链接并替换(后缀&…...
基于STM32 + FPGA 的软体机器人的 CAN总线运动控制器的设计
针对在软体机器人控制时,多电机协同控制过程中难度大、通用性差、协同性差等缺点,设计了基于 ARM和 FPGA的软体机器人的控制器局域网络 ( controller area network,CAN) 总线运动控制器,采用 ARMCortex-M4 …...
ROC曲线和AUC值
ROC曲线(Receiver Operating Characteristic,受试者工作特征)评价分类模型的可视化工具,是一条横纵坐标都限制在0-1范围内的曲线横坐标是假正率FPR,错误地判断为正例的概率纵坐标是真正率TPR,正确地判断为正…...
【vue.js】在网页中实现一个金属抛光质感的按钮
文章目录前言效果电脑效果手机效果说明完整代码index.html前言 诶?这有一个按钮(~ ̄▽ ̄)~,这是一个在html中实现的具有金属质感并且能镜面反射的按钮~ 效果 电脑效果 手机效果 说明 主要思路是使用 navig…...
android实现评论区功能
效果 activity_detail.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http…...
Java每日一练(20230319)
目录 1. 最大矩形 🌟🌟🌟 2. 回文对 🌟🌟🌟 3. 给表达式添加运算符 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练…...
Redis缓存双写一致性
目录双写一致性Redis与Mysql双写一致性canal配置流程代码案例双写一致性理解缓存操作细分缓存一致性多种更新策略挂牌报错,凌晨升级先更新数据库,在更新缓存先删除缓存,在更新数据库先更新数据库,在删除缓存延迟双删策略总结双写一致性 Redis与Mysql双写一致性 canal 主要是…...
【2023-Pytorch-检测教程】手把手教你使用YOLOV5做交通标志检测
项目下载地址:YOLOV5交通标志识别检测数据集代码模型教学视频-深度学习文档类资源-CSDN文库 交通标志的目标检测算法在计算机视觉领域一直属于热点研究问题,改进的优化算法不断地被提出。国内外许多学者针对现有的目标检测方法中网络结构、目标定位、损…...
Java中的二叉树
文章目录前言一、树形结构(了解)1.1 概念1.2 概念(重要)1.3 树的表示形式(了解)1.4 树的应用二、二叉树(重点)2.1 概念2.2 两种特殊的二叉树2.3 二叉树的性质2.5 二叉树的存储2.5 二…...
基于 gma 绘制古代洛阳 5 大都城遗址空间分布地图
了解 gma gma 是什么? gma 是一个基于 Python 的地理、气象数据快速处理和数据分析函数包(Geographic and Meteorological Analysis,gma)。gma 网站:地理与气象分析库。 gma 的主要功能有哪些? 气候气象&a…...
分析 Spring 的依赖注入模式
一、依赖注入二、Field Injection优点缺点三、Constructor Injection优点1. 容易发现 code smell优点2. 容易厘清依赖关系优点3. 容易写单元测试优点4. Immutable Object缺点:循环依赖四、总结一、依赖注入 依赖注入 (Dependency Injection,…...
IntelliJ IDEA创建Servlet
目录 ——————————————————————————————— 一、创建Java项目 1、创建java项目 2、选择java 3、next 4、给项目命名 5、新创建完java项目的目录结构 二、变java为servlet项目 1、变servlet项目 2、选择Web Application 3、更新完成后的目录…...
Spring Boot如何让自己的bean优先加载
背景介绍 在一些需求中,可能存在某些场景,比如先加载自己的bean,然后自己的bean做一些DB操作,初始化配置问题,然后后面的bean基于这个配置文件,继续做其他的业务逻辑。因此有了本文的这个题目。 实现方法…...
LeetCode分类刷题----动态规划
动态规划509.斐波那契数列70.爬楼梯746.使用最小花费怕楼梯62.不同路径63.不同路径||343.整数拆分96.不同的二叉搜索树01背包问题416.分割等和子集1049.最后一块石头的重量||494.目标和474.一和零完全背包问题518.零钱兑换||377.组合总和IV322.零钱兑换279.完全平方数139.单词拆…...
今年好像没有金三银四了?
大家好,我是记得诚。 金三银四,是换工作的高峰期,新的一年结束了,在年前拿完年终奖,在年后3月和4月换个满意的工作。 单从我公司来看,目前还没有一个人离职,往年离职率是要高一些的。 还有我…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...
