在函数调用点插入函数本体,然后移除该函数。
将所有对该变量的引用动作,替换为对它赋值那个表达式本身。
将这个表达式提炼到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可被其他函数使用。
将复杂表达式的结果放进一个临时变量,以此变量名称来解释表达式用途。
「动机」
在条件逻辑中,引入解释性变量特别有价值,你可以用这项重构将每个条件子句提炼出来,以一个良好命名的临时变量来解释对应条件子句的意义。使用这项重构的另一种情况是,在较长算法中,可以运用临时变量来解释每一步运算的意义。
针对每次赋值,创造一个独立、对应的临时变量。
「动机」
如果临时变量被赋值超过一次,就意味着它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换为多个临时变量,每个变量只承担一个责任。同一个临时变量承担两件不同的事情,会另代码阅读者糊涂。
/**
@startTime 2020-12-21 21:30
@endTime 2020-12-21 23:50
@startPage 131
@endPage 188
@efficiency 188/6 = 31.3页/天
@needDays 412/31.3 = 13天
@overDay 2020-12-16 + 13天 = 2020-12-28
*/
**以一个临时变量取代该参数的位置。
首先,我要确定大家都清楚“对参数赋值”这个说法的意思。如果你把一个名为user的对象作为参数传给某个函数,那么“对参数赋值”意味着改变user,使它引用另外一个对象。如果你在“被传入对象”身上进行什么操作,那没问题,我也总是这样干。我只针对“user被改而指向另一个对象”这种情况来讨论。**
你有一个大型函数,其中对局部变量的使用使你无法采用提取函数,将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段,然后你可以在同一个对象中将这个大型函数分解为多个小型函数。
「动机」
我在本书中不断向读者强调小型函数的优美动人。只要将相对独立的代码从大型函数中提炼出来,就可以大大提高代码的可读性。
「做法」
建立一个新类,根据待处理函数的用途,为这个类命名。
在新类中建立一个final字段,用以保存原先大型函数所在的对象。我们将这个字段称为“源对象”。同时,针对原函数的每个临时变量和每个参数,在新类中建立一个对应的字段保存之。
在新类中建立一个构造函数,接收源对象及原函数的所有参数作为参数。
在新类中建立一个compute函数。
将原函数的代码复制到compute()函数中。如果需要调用源对象的任何函数,请通过源对象字段调用。
编译。
将旧函数的函数本体替换为compute()函数。
将函数本体替换为另一种算法。
============================================================================
你的程序中,有个函数与其所在类之外的另一个类进行更多的交流,在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托关系,或是将旧函数完全移除。
“搬移函数”是重构理论的支柱。如果一个类有太多行为,或如果一个类与另一个类有太多合作而形成高度耦合,我就会搬移函数。通过这种手段,可以使系统中的类更简单,这些类最终也将更干净利落地实现系统交付的任务。
某个类做了应该由两个类做的事,建立一个新类,将相关的字段和函数从旧类搬移至新类。
某个类没有做太多的事情,将这个类的所有特性搬移至另一个类中,然后移除该类。
客户端通过一个委托类来调用另一个对象时,在服务类上建立客户所需的所有函数,用以隐藏委托关系。
public Person getManager(){
return _department.getManager();
}
只有完成了对Department所有函数的委托关系,并相应修改了Person的所有客户,我就可以移除Person中的访问函数getDepartment()了。
某个类做了过多的简单委托动作时,让客户直接调用受委托类。
Date start = new Date(previous.getYear(),previous.getMonth(),previous.getDate()+1);
变为
Date start = nextDay(previous);
private static Date nextDay(previous.getYear(),previous.getMonth(),previous.getDate()+1);
貌似懂了一点。
外加函数终归是权宜之计,如果有可能,仍然应该讲这些函数搬移至它们应该在的地方。
你需要为服务类提供一些额外函数,但你无法修改这个类,建立一个新类,使它包含这些额外函数,让这个扩展类成为原类的子类或包装类。
「动机」
在子类和包装类之间做选择时,我通常首选子类,因为这样的工作量比较少。制作子类的最大障碍在于,如果原数据是可修改的,一个修改动作无法改变两个副本,这时就必须改用包装类
「做法」
建立一个扩展类,将它作为原始类的子类或包装类。
在扩展类中加入转型构造函数,所谓转型构造函数,是指“接受原对象作为参数”的构造函数。如果采用子类化方案,那么转型构造函数应该调用适当的超类构造函数;如果采用包装类方案,那么转型构造函数应该将它得到的传入参数以实例变量的形式保存起来,用作接受委托的原对象。
在扩展类中加入新特性。
根据需要,将原对象改为扩展对象。
将针对原始类定义的所有外加函数搬移至扩展类中。
=========================================================================
为字段建立取值/设置函数,并且只以这些函数来访问字段。
你有一个数据项,需要与其它数据和行为一起使用才有意义,将数据项变成对象。
你有一个引用对象,很小且不可变,而且不易管理,此时,将它变成一个值对象。
要在引用对象和值对象之间做出选择,有时并不容易。做出选择后,你常会需要一条回头路。
如果引用对象开始变得难以使用,也许就应该将它变为值对象。引用对象必须被某种方式控制,你总是必须向其控制者请求适当的引用对象。它们可能造成内存区域之间错综复杂的关联。在分布式系统和并发系统中,不可变的值对象特别有用,因为你无需考虑它们的同步问题。
以对象取代数组,对于数组中的每一个元素,以一个字段来表示。
「动机」
数组是一种常见的用以组织数据的结构。不过,它们应该只用于“以某种顺序容纳一组相似对象”。有时你会发现,一个数组容纳了多种不同对象,这会给用户带来麻烦,因为它们很难记住像“数组的第一个元素是人名”这样的约定。对象就不同了,你可以运用字段名称和函数名称来传达这样的信息,也无需使用注释。而且使用对象,你还可以将信息封装起来,并使用“搬移函数”将它加上相关行为。
我之前做过一个数据上传系统,有这么个结构:
Map<String,String[]> hashMap = new HashMap<String,String[]>();
String[] data = new Data[4];
data[0] = “1”;//状态state
data[1] = “1”;//延展状态exstate
data[2] = “1”;//数值
data[3] = “2020-12-21 23:22:00”;//数据生成时间
String key = “01A01”;//测点编号
hashMap.put(key,data);
…
for(String key : hashMap.keySet){
//状态state、延展状态exstate、数值、数据生成时间
String[] data = hashMap.get(key);
String state = data[0];
String exstate = data[1];
String value = data[2];
String time = data[3]’
}
因为数据存在基本数据、实时数据、分钟累计数据,这种结构的代码项目中比比皆是,写的那叫一个烂,这个上传程序折磨的我苦不堪言,往事不堪回首。
「做法」
@Data
public class BasicData(){
private int state;
private int exstate;
private double value;
private Date time;
}
Map<String,BasicData> hashMap = new HashMap<String,BasicData>();
BasicData basicData = new BasicData();
basicData.setState = “1”;
basicData.setExstate = “1”;
basicData.setValue = 3.12;
String str = “2020-12-21 23:22:00”;
basicData.setTime = DateUtil.StringToDate(str,“yyyy-MM-dd hh:mm:ss”);
String key = “01A01”;//测点编号
hashMap.put(key,basicData);
…
for(String key : hashMap.keySet){
//状态state、延展状态exstate、数值、数据生成时间
BasicData basicData = hashMap.get(key);
String state = basicData.getState();
String exstate = basicData.getExstate();
double value = basicData.getValue();
Date time = basicData.getTime();
}
多么痛的领悟。
其实很简单。
/**
@startTime 2020-12-22 21:30
@endTime 2020-12-22 22:50
@startPage 189
@endPage 235
@efficiency 235/7 = 33.6页/天
@needDays 412/33.6 = 12天
@overDay 2020-12-16 + 12天 = 2020-12-27
*/
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
每年转战互联网行业的人很多,说白了也是冲着高薪去的,不管你是即将步入这个行业还是想转行,学习是必不可少的。作为一个Java开发,学习成了日常生活的一部分,不学习你就会被这个行业淘汰,这也是这个行业残酷的现实。
如果你对Java感兴趣,想要转行改变自己,那就要趁着机遇行动起来。或许,这份限量版的Java零基础宝典能够对你有所帮助。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
!**
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
每年转战互联网行业的人很多,说白了也是冲着高薪去的,不管你是即将步入这个行业还是想转行,学习是必不可少的。作为一个Java开发,学习成了日常生活的一部分,不学习你就会被这个行业淘汰,这也是这个行业残酷的现实。
如果你对Java感兴趣,想要转行改变自己,那就要趁着机遇行动起来。或许,这份限量版的Java零基础宝典能够对你有所帮助。
[外链图片转存中…(img-NgTXK6p3-1713386372122)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数