『重构--改善既有代码的设计』读书笔记----Self Encapsulate Field
如果你直接访问一个字段,你就会和这个字段直接的耦合关系变得笨拙。也就是说当这个字段权限更改,或者名称更改之后你的客户端代码都需要做相应的改变,此时你可以为这个字段建立设值和取值函数并且只以这些函数来访问字段。
自古以来,面向对象关于字段访问就存在两个派系,其中一个派系认为,如果在该字段所在的类中,你就可以自由访问他,不需要通过间接的函数来获得。另外一派认为,即使在这个类中你也应该只使用设值和取值函数来间接访问。
当然了,间接访问可以带来的额外好处就是你可以通过子类来覆写函数做到改变获取数据的途径。他还可以让你支持灵活的数据管理方式,比如延迟初始化等。直接访问变量的好处也有,就是可以让我们阅读代码的人给我们更加明确清晰的思路,不要追函数追到一般才发现这原来只是一个简单的取值函数,从而影响我们的判断。
在面对这种选择的时候,我支持作者的观点,我在该字段本类中我会优先去使用直接访问的形式,直到这种直接访问的形式给我带来麻烦的时候,此时我才会去选择改变才用间接访问的方式,这也是重构带给我们的魅力,他可以让我们自由改变我们需要的方式。
如果你想访问超类中的一个字段,却又想在子类中对这个变量的访问改为一个计算后的值(或者针对那种简单的类型码判断,基类和子类返回不一样的类型码)这就是使用Self Encapsulate Filed的时候,字段自我封装只是第一步,完成自我封装之后,你可以在子类中根据自己的需要随意覆写取值/设值函数。
做法:
- 为待封装字段建立设值/取值函数。
- 找出该字段的所有引用点,将他们全部改为设值/取值函数。如果引用点要读取字段值,就将他改为调用取值函数。如果引用点要给字段,就将他改为设值函数。当然这里也有一个小技巧帮你可以更快更全的找到所有引用点,就是你通过对字段改名,借助编译器帮你找到所有这些引用点。
- 将该字段声明为private.
- 复查,确保找到所有引用点。
- 编译,测试。
例子:
class IntRange
{
public:
IntRange(int low, int high) :
m_low(low),
m_high(high)
{
} bool includes(int arg)
{
return arg >= m_low && arg <= m_high;
} void grow(int factor)
{
m_high = m_high * factor;
}
private:
int m_low;
int m_high;
}
为了封装m_low和m_high我们定义取值/设值函数,并使用它们。
class IntRange
{
public:
IntRange(int low, int high) :
m_low(low),
m_high(high)
{
} bool includes(int arg)
{
return arg >= low() && arg <= high();
} void grow(int factor)
{
m_high = m_high * factor;
} virtual int low() const
{
return m_low;
} virtual int high() const
{
return m_high;
}
private:
int m_low;
int m_high;
};
同时这里有一点需要注意的就是你的取值函数和设值函数如果是在构造函数中进行调用的你就需要注意,现在C++默认在构造函数中是不会呈现多态性的,也就是说如果你在基类的构造函数中放了一个虚函数,当你创建子类的时候,当进入到基类的构造函数的时候并不会去调用子类的虚函数,依然还是去调用基类的虚函数。
同时还需要注意的就是默认一般来说,设值函数被认同是在对象创建之后才使用的,所以初始化过程中的行为可能与设值函数行为不同,这种情况下,你要么就是在构造函数中直接访问字段,要么就是单独创建另一个初始化函数。
IntRange(int low, int high) :
m_low(low),
m_high(high)
{
initialize(low, high);
} void initialize(int low, int high)
{
m_low = low;
m_high = high;
}
当然,现在你也许看不到什么价值,但如果你一旦拥有了子类,上述体现的价值就出来了。
class CappedRange : public IntRange
{
public:
CappedRange(int low, int high, int cap) :
IntRange(low, high),
m_cap(cap)
{
} virtual int cap() const
{
return m_cap;
} virtual int high() const
{
return qMin(IntRange::high(), cap());
} private:
int m_cap;
};
现在你可以在high()中进行覆写,从而加上范围上限的考虑而不必修改IntRange的任何行为。
『重构--改善既有代码的设计』读书笔记----Self Encapsulate Field的更多相关文章
- 『重构--改善既有代码的设计』读书笔记----Extract Method
在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...
- 『重构--改善既有代码的设计』读书笔记---Duplicate Observed Data
当MVC出现的时候,极大的推动了Model与View分离的潮流.然而对于一些已存在的老系统或者没有维护好的系统,你都会看到当前存在大把的巨大类----将Model,View,Controller都写在 ...
- 『重构--改善既有代码的设计』读书笔记----Move Field
在类与类之间搬移状态和行为,是重构过程中必不可少的步骤.很有可能在你现在觉得正常的类,等你到了下个礼拜你就会觉得不合适.或者你在下个礼拜创建了一个新的类并且你需要讲现在类的部分字段和行为移动到这个新类 ...
- 『重构--改善既有代码的设计』读书笔记----Change Value to Reference
有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...
- 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object
有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...
- 『重构--改善既有代码的设计』读书笔记----Replace Array with Object
如果你有一个数组,其中的元素各自代表不同东西,比如你有一个 QList<QString> strList; 其中strList[0]代表选手姓名,strList[1]代表选手家庭住址,很显 ...
- 『重构--改善既有代码的设计』读书笔记----Move Method
明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...
- 『重构--改善既有代码的设计』读书笔记----Replace Data Value with Object
当你在一个类中使用字段的时候,发现这个字段必须要和其他数据或者行为一起使用才有意义.你就应该考虑把这个数据项改成对象.在开发初期,我们对于新类中的字段往往会采取简单的基本类型形式来保存,但随着我们开发 ...
- 『重构--改善既有代码的设计』读书笔记----Substitute Algorithm
重构可以把复杂的东西分解成一个个简单的小块.但有时候,你必须壮士断腕删掉整个算法,用简单的算法来取代,如果你发现做一件事情可以有更清晰的方式,那你完全有理由用更清晰的方式来解决问题.如果你开始使用程序 ...
随机推荐
- hdoj 3342 Legal or Not【拓扑排序】
Legal or Not Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- codeforces 710C
C. Magic Odd Square time limit per test 1 second memory limit per test 256 megabytes input standard ...
- bzoj3907: 网格
http://www.cnblogs.com/Tunix/p/4354348.html #include<cstdio> #include<cstring> #include& ...
- c#委托和事件(下) 分类: C# 2015-03-09 08:42 211人阅读 评论(0) 收藏
C#中的委托和事件(下) 引言 如果你看过了 C#中的委托和事件 一文,我想你对委托和事件已经有了一个基本的认识.但那些远不是委托和事件的全部内容,还有很多的地方没有涉及.本文将讨论委托和事件一些更为 ...
- asp.net 动态添加多附件上传.
最近有人问起动态多文件上传,想要做到类似于邮箱添加附件的效果,这个功能其实比较简单,就是往form中添加file元素.在用户选择完文件后,再添加一个file控件,由于file控件过多,视觉上不好看,所 ...
- [转]Animation 动画详解(一)——alpha、scale、translate、rotate、set的xml属性及用法
转载:http://blog.csdn.net/harvic880925/article/details/39996643 前言:这几天做客户回访,感触很大,用户只要是留反馈信息,总是一种恨铁不成钢的 ...
- 【ActionScript】ActionScript3.0对舞台组件的增删改查
以一个样例来说明ActionScript3.0对舞台组件的增删改查 例如以下图: 在Flash执行的时候,通过脚本.斜向下生成text0-text9十个文本节点. 提供两个功能. 1.在右上角,用户输 ...
- TOJ 2732存钱计划(三)(单源最短路)
存钱计划(三) 时间限制(普通/Java):1000MS/30000MS 运行内存限制:65536KByte 总提交: 18 测试通过: 16 描述 TZC的店铺比较 ...
- MySQL 错误日志(Error Log)
同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分.MySQL有几种不同的日志文件.通常包括错误日志文件,二进制日志,通用日志,慢查询日志,等等. 这些日志能够帮助我们定位mysqld ...
- android 40 Io编程
Io编程:内存卡和sd卡.字符串存入内存卡然后读出来. activity: package com.sxt.day06_06; import java.io.FileInputStream; impo ...