重构改善既有代码设计--重构手法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 ...
随机推荐
- Python if后直接跟数字或字符串
(1)如果if后面的条件是数字,只要这个数字不是0,python都会把它当做True处理,见下面的例子 if 15: print 'YES' 输出YES,但是如果数字是0,就会被认为是False. ( ...
- Redis 列表(List)
Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边),一个列表最多可以包含2^32-1个元素(4294967295,每个列表超过40亿个元素). ...
- Maven基本理解
转 maven(一) maven到底是个啥玩意~ 我记得在搞懂maven之前看了几次重复的maven的教学视频.不知道是自己悟性太低还是怎么滴,就是搞不清楚,现在弄清楚了,基本上入门了.写该篇博文,就 ...
- mysql的程序组成
MySQL的程序组成 1:客户端 mysql:客户端程序 mysqldump:mysql备份工具 mysqladmin:mysql管理工具 mysqlbinlog:二进制日志查询工具 2:服务端 my ...
- 使用.bat文件运行ant的build.xml
1.新建一个txt文件 2.复制下面命令到txt文件 echo "Start build..." call ant.bat -f "E:\build.xml" ...
- vue render & array of components & vue for & vue-jsx
vue render & array of components & vue for & vue-jsx https://www.cnblogs.com/xgqfrms/p/1 ...
- 第92天:CSS3中颜色和文本属性
一.颜色的表示方式 1. rgba(255,0,0,0.1) rgba是代表Red(红色) Green(绿色) Blue(蓝色)和 Alpha透明度.虽然它有的时候被描述为一个颜色空间 新增了RGB ...
- python的N个小功能之正则匹配
1.. 匹配任意除换行符“\n”外的字符:2.*表示匹配前一个字符0次或无限次:3.+或*后跟?表示非贪婪匹配,即尽可能少的匹配,如*?重复任意次,但尽可能少重复,惰性匹配:4. .*? 表示匹配任意 ...
- 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息
题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...
- py2exe使用总结
假如你用python写了个小程序,想给别人用或者给别人演示,但他电脑里没装python.wxpython等,这时候你可以试试py2exe,它是一个将python脚本转换成windows上的可执行程序( ...