如果你直接访问一个字段,你就会和这个字段直接的耦合关系变得笨拙。也就是说当这个字段权限更改,或者名称更改之后你的客户端代码都需要做相应的改变,此时你可以为这个字段建立设值和取值函数并且只以这些函数来访问字段。

自古以来,面向对象关于字段访问就存在两个派系,其中一个派系认为,如果在该字段所在的类中,你就可以自由访问他,不需要通过间接的函数来获得。另外一派认为,即使在这个类中你也应该只使用设值和取值函数来间接访问。

当然了,间接访问可以带来的额外好处就是你可以通过子类来覆写函数做到改变获取数据的途径。他还可以让你支持灵活的数据管理方式,比如延迟初始化等。直接访问变量的好处也有,就是可以让我们阅读代码的人给我们更加明确清晰的思路,不要追函数追到一般才发现这原来只是一个简单的取值函数,从而影响我们的判断。

在面对这种选择的时候,我支持作者的观点,我在该字段本类中我会优先去使用直接访问的形式,直到这种直接访问的形式给我带来麻烦的时候,此时我才会去选择改变才用间接访问的方式,这也是重构带给我们的魅力,他可以让我们自由改变我们需要的方式。

如果你想访问超类中的一个字段,却又想在子类中对这个变量的访问改为一个计算后的值(或者针对那种简单的类型码判断,基类和子类返回不一样的类型码)这就是使用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的更多相关文章

  1. 『重构--改善既有代码的设计』读书笔记----Extract Method

    在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...

  2. 『重构--改善既有代码的设计』读书笔记---Duplicate Observed Data

    当MVC出现的时候,极大的推动了Model与View分离的潮流.然而对于一些已存在的老系统或者没有维护好的系统,你都会看到当前存在大把的巨大类----将Model,View,Controller都写在 ...

  3. 『重构--改善既有代码的设计』读书笔记----Move Field

    在类与类之间搬移状态和行为,是重构过程中必不可少的步骤.很有可能在你现在觉得正常的类,等你到了下个礼拜你就会觉得不合适.或者你在下个礼拜创建了一个新的类并且你需要讲现在类的部分字段和行为移动到这个新类 ...

  4. 『重构--改善既有代码的设计』读书笔记----Change Value to Reference

    有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...

  5. 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

    有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...

  6. 『重构--改善既有代码的设计』读书笔记----Replace Array with Object

    如果你有一个数组,其中的元素各自代表不同东西,比如你有一个 QList<QString> strList; 其中strList[0]代表选手姓名,strList[1]代表选手家庭住址,很显 ...

  7. 『重构--改善既有代码的设计』读书笔记----Move Method

    明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...

  8. 『重构--改善既有代码的设计』读书笔记----Replace Data Value with Object

    当你在一个类中使用字段的时候,发现这个字段必须要和其他数据或者行为一起使用才有意义.你就应该考虑把这个数据项改成对象.在开发初期,我们对于新类中的字段往往会采取简单的基本类型形式来保存,但随着我们开发 ...

  9. 『重构--改善既有代码的设计』读书笔记----Substitute Algorithm

    重构可以把复杂的东西分解成一个个简单的小块.但有时候,你必须壮士断腕删掉整个算法,用简单的算法来取代,如果你发现做一件事情可以有更清晰的方式,那你完全有理由用更清晰的方式来解决问题.如果你开始使用程序 ...

随机推荐

  1. Selenium如何实现dropbar移动

    遇到这个拖拽的dropbar,如何实现呢,, 经过网上查找,可以用Action的方式实现或者js来控制 原理:移动按钮的同时,数字也随着变化 解决方法:1.最简单的就是直接在文本框输入相应的数字 2. ...

  2. java基础(十)面向对象(五)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

  3. poj 2960 S-Nim(SG函数)

    S-Nim Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3694   Accepted: 1936 Description ...

  4. Import larger wordpress xml file

    The maximum size is controlled by two PHP settings: upload_max_filesize, and post_max_size. These ar ...

  5. 0ull 是什么意思?

    unsigned long long 类型的0 同理:#define     DEV_IIC1             ( (u64)1 <<  7ULL)    这个作用是64位中的第7 ...

  6. 上海Uber优步司机奖励政策(1月25日~1月31日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  7. java 新手

    public class hello{ public static void main(String args[]){ int a=23,b=32,c=34; int s=Math.max(a,c); ...

  8. 【Android - MD】之NavigationView的使用

    NavigationView是Android 5.0新特性--Material Design中的一个布局控件,可以结合DrawerLayout使用,让侧滑菜单变得更加美观(可以添加头部布局). Nav ...

  9. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(42)-工作流设计01

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(42)-工作流设计01 工作流在实际应用中还是比较广泛,网络中存在很多工作流的图形化插件,可以做到拉拽的工 ...

  10. 使用dom4j解析xml文件,并封装为javabean对象

    dom4j是一个java的XML api,性能优异.功能强大.易于使用.这里使用dom4j对xml文件进行解析,并完成对文件的封装. 实现对xml文件的解析,主要使用到的是dom4j中的SAXRead ...