重构改善既有代码设计--重构手法18:Self Encapsulate Field (自封装字段)
你直接访问一个值域(field),但与值域之间的耦合关系逐渐变得笨拙。
为这个值域建立取值/设值函数(getting/setting methods),并且只以这些函数来访问值域。
private int _low, _high;
boolean includes(int arg) {
return arg >= _low && arg <= _high;
}
==〉
private int _low, _high;
boolean includes(int arg) {
return arg >= getLow() && arg <= getHigh();
}
int getLow() {return _low;}
int getHigh() {return _high;}
动机
如果你想访问superclass中的一个值域,却又想在subclass中将[对这个变量的访问]改为一个计算后的值,这就是最该使用Self Encapsulate Field(171)的时候。[值域自我封装]只是第一步。完成自我封装之后,你可以在subclass中根据自己的需要随意覆写取值/设值函数(getting/setting methods)。
作法
1. 为[待封装值域]建立取值/设值函数(getting/setting methods)。
2. 找出该值域的所有引用点,将它们全部替换为[对于取值/设值函数的调用]。
如果引用点是[读值]值域值,就将它替换为[调用取值函数];如果引用点是[设定]值域值,就将它替换为[调用设值函数]。
你可以暂时为设值域改名,让编译器帮助你查找引用点。
3. 将该值域声明为private。
4. 复查,确保找出所有引用点。
5. 编译,测试。
class IntRange {
private int _low, _high;
boolean includes(int arg) {
return arg >= _low && arg <= _high;
}
void grow(int factor) {
_high = _high * factor;
}
IntRange(int low, int high) {
_low = low;
_high = high;
}
}
为了封装_low和_high这两个值域,我先定义[取值/设值函数](如果此前没有定义的话),并使用它们:
class IntRange {
private int _low, _high;
boolean includes(int arg) {
return arg >= _low && arg <= _high;
}
void grow(int factor) {
SetHigh(getHigh()*factor);
}
int getLow() {
return _low;
}
int getHigh() {
return _high;
}
void setLow(int arg) {
_low = arg;
}
void setHigh(int arg) {
_high = arg;
}
}
使用本项重构时,一般说来,设值函数被认为应该在[对象创建后]才使用,所以初始化过程中的行为有可能与设值函数的行为不同。这种情况下,我允许在构造函数中直接访问值域,要不就是建立另一个独立的初始化函数:
IntRange(int low, int high) {
initialize(low, high);
}
private void initialize(int low, int high) {
_low = low;
_high = high;
}
一旦你拥有一个subclass,上述所有动作的价值就体现出来了。如下所示:
class CappedRange extends IntRange {
CappedRange(int low, int high, int cap) {
super(low, high);
_cap = cap;
}
private int _cap;
int getCap() {
return _cap;
}
int getHigh() {
return Math.min(super.getHigh(), getCap());
}
}
现在,我可以CappedRange class中覆写getHigh(),从而加入对cap的考虑,而不必修改IntRange class的任何行为。
重构改善既有代码设计--重构手法18:Self Encapsulate Field (自封装字段)的更多相关文章
- 重构改善既有代码设计--重构手法11:Move Field (搬移字段)
你的程序中,某个字段被其所驻类之外的另一个类更多的用到.在目标类建立一个新字段,修改源字段的所有用户,令它们改用新字段. 动机:在类之间移动状态和行为,是重构过程中必不可少的措施.随着系 ...
- 重构改善既有代码设计--重构手法16:Introduce Foreign Method (引入外加函数)&& 重构手法17:Introduce Local Extension (引入本地扩展)
重构手法16:Introduce Foreign Method (引入外加函数)你需要为提供服务的类增加一个函数,但你无法修改这个类.在客户类中建立一个函数,并以第一参数形式传入一个服务类实例. 动机 ...
- 重构改善既有代码设计--重构手法08:Replace Method with Method Object (以函数对象取代函数)
你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型 ...
- 重构改善既有代码设计--重构手法07:Remove Assignments to Parameters (移除对参数的赋值)
代码对一个 参数赋值.以一个临时变量取代该参数的位置. int Discount(int inputVal, int quantity, int yearTodate) { if (input ...
- 重构改善既有代码设计--重构手法05:Introduce Explaining Variable (引入解释性变量)
发现:你有一个复杂的表达式. 解决:将该复杂的表达式(或其中的部分)的结果放进一个临时变量,并以此变量名称来解释表达式用途. //重构前 if((platform.toUpperCase().in ...
- 重构改善既有代码设计--重构手法04:Replace Temp with Query (以查询取代临时变量)
所谓的以查询取代临时变量:就是当你的程序以一个临时变量保存某一个表达式的运算效果.将这个表达式提炼到一个独立函数中.将这个临时变量的所有引用点替换为对新函数的调用.此后,新函数就可以被其他函数调用. ...
- 重构改善既有代码设计--重构手法02:Inline Method (内联函数)& 03: Inline Temp(内联临时变量)
Inline Method (内联函数) 一个函数调用的本体与名称同样清楚易懂.在函数调用点插入函数体,然后移除该函数. int GetRating() { return MoreThanfiveLa ...
- 重构改善既有代码设计--重构手法01:Extract Method (提炼函数)
背景: 你有一段代码可以被组织在一起并独立出来.将这段代码放进一个独立函数,并让函数名称解释该函数的用途. void PrintOwing(double amount) { PrintBanner() ...
- 重构改善既有代码设计--重构手法19:Replace Data Value with Object (以对象取代数据值)
你有一笔数据项(data item),需要额外的数据和行为. 将这笔数据项变成一个对象. class Order... private string customer; ==> class Or ...
随机推荐
- http://deepdish.io/2015/04/28/creating-lmdb-in-python/
http://deepdish.io/2015/04/28/creating-lmdb-in-python/
- 明白JavaScript原型链和JavaScrip继承
原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...
- mysql 慢查询,查询缓存,索引,备份,水平分割
1.开启慢查询 在mysql的配置文件my.ini最后增加如下命令 [mysqld]port=3306slow_query_log =1long_query_time = 1 2.查看慢查询记录 默认 ...
- jenkins 配置git 学习
由于Jenkins没有默认安装Git插件,需要Git库同步时候,需要手动选择安装git插件 在“系统管理”->“管理插件”中找到,“可选插件”选项卡.“过滤“(一个名为过滤的搜素窗口)中可以用键 ...
- Vue 自定义指令练习
Vue.directive(id,definition)注册一个全局自定义指令,接收两个参数,指令ID以及定义对象 取值: <div v-demo="{ color: 'white', ...
- 【bzoj4305】数列的GCD 组合数学+容斥原理
题目描述 给出一个长度为N的数列{a[n]},1<=a[i]<=M(1<=i<=N). 现在问题是,对于1到M的每个整数d,有多少个不同的数列b[1], b[2], ..., ...
- 【容斥原理,莫比乌斯反演】用容斥替代莫比乌斯反演第二种形式解决gcd统计问题
名字虽然很长.但是其实很简单,对于这一类问题基本上就是看你能不能把统计的公式搞出来(这时候需要一个会推公式的队友) 来源于某次cf的一道题,盼望上紫的我让潘学姐帮我代打一道题,她看了看跟我说了题解,用 ...
- BeanUtils介绍及其使用
BeanUtils工具由Apache软件基金组织编写,提供给我们使用,主要解决的问题是:把对象的属性数据封装到对象中.在整个J2EE的编程过程中,我们经常会从各种配置文件中读取相应的数据,需要明白的一 ...
- 洛谷 P3539 [POI2012]ROZ-Fibonacci Representation 解题报告
P3539 [POI2012]ROZ-Fibonacci Representation 题意:给一个数,问最少可以用几个斐波那契数加加减减凑出来 多组数据10 数据范围1e17 第一次瞬间yy出做法, ...
- Linux内核分析5
周子轩 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.学习总结 通过gdb ...