在类与类之间搬移状态和行为,是重构过程中必不可少的步骤。很有可能在你现在觉得正常的类,等你到了下个礼拜你就会觉得不合适。或者你在下个礼拜创建了一个新的类并且你需要讲现在类的部分字段和行为移动到这个新类中。如果你发现在一个类中的某个字段,更多的被别的类的函数所使用,包括设值set和取值get函数锁取用,那么你就应该考虑搬移这个字段。当然,你也可能会去考虑是否使用Move Method去搬移这些使用这个字段的函数到这个字段的源类中去,这取决于你是否能够接受接口的变化,如果这些函数更加适合待在原地不动,那么你就应该选择Move Field。如果你此时需要将行为和字段都搬移出去出去形成一个新类(Extract Class),那么此时你应该先Move Field之后再Move Method。

做法:

  • 如果你需要搬移的字段是public级别的,你需要使用Encapsulate Field先将它封装起来。如果你可能需要移动那些频繁访问该字段的函数,或者有很多函数访问某个字段,那么Self Encapsulate Field可能对你有帮助。
  • 编译,测试。
  • 在目标类建立和源类相同的字段,并建立相应的设值和取值函数。
  • 编译目标类。
  • 决定如何在源对象中引用目标对象。首先查看是否有现成的字段或者函数可以取得目标对象,如果没有就尝试能不能建立一个这样的函数,如果还是不能,就考虑在源类新建一个字段来存放目标对象,这可能是永久性的修改,但也可能因为后续的重构你会把这个新建字段给删除。
  • 删除源字段。
  • 将所有对源字段的引用替换为对某个目标函数的调用。如果需要读取变量,就把对源字段的引用替换为对目标取值函数的调用,如果需要对变量赋值,就把对源字段的引用替换为对目标设值函数的调用。如果源字段不是private级别的,就必须在源类的所有子类中查找替换对源字段的引用,并进行替换。
  • 编译,测试。

例子:

class Account...
private:
AccountType m_type;
double m_interestRate;
public:
double interestForAmountdays(double amount, int days)
{
return m_interestRate * amount * days / ;
}

我想把m_interestRate移到AccountType中去,我们可以看到,interestForAmountdays这个函数已经引用了这个字段,接下来我们要做的就是在AccountType中建立同样的字段,并设置取值和设值函数

class AccountType...
private:
double m_interestRate;
public:
void setInterestRate(double arg)
{
m_interestRate = arg;
}
double interestRate() const
{
return m_interestRate;
}

添加完成后,我们对目标类进行编译。现在我们需要将源类中对原字段访问的函数转而使用对目标取值函数的调用,然后我们删除源类中的字段。删除源字段也可以让编译器帮我们查找出所有需要修改的函数。

double interesetForAmountdays(double amount, int days)
{
return m_type.interestRate() * amount * days / ;
}

这里演示的是单一函数存在对源字段的引用。如果这里有很多函数都对原字段进行过引用,我们可以先使用Self Encapsulate Field进行自我封装。

class Account...
private:
AccountType m_type;
double m_interestRate;
public:
double interesetForAmountdays(double amount, int days)
{
return interestRate() * amount * days / ;
} void setInterestRate(double arg)
{
m_interestRate = arg;
} double interestRate() const
{
return m_interestRate;
}

这个带来的好处就是当我们搬移字段中之后,我们不需要去追踪所有引用字段的函数,我们只需要去修改取值函数和设值函数就可以达到所有函数的修改。

double interesetForAmountdays(double amount, int days)
{
return interestRate() * amount * days / ;
} void setInterestRate(double arg)
{
m_type.setInterestRate(arg);
}
double interestRate() const
{
return m_type.interestRate();
}

当然,如果你也可以让这些调用访问函数的用户直接去访问目标对象。Self Encapsulate Field可以让你的重构进行小步伐前进,很有帮助。小步伐前进也是重构能够稳步前进的秘诀,可以让你的工作和生活变得更加轻松。特别值得一提的是,如果你一开始就使用Self Encapsulate Field,如果此时你需要使用Move Method,在这个函数中可能正好有对该字段的访问

double interesetForAmountdays(double amount, int days)
{
return interestRate() * amount * days / ;
}

他在Account类中,被你搬移到了AccountType中,因为你没有在函数里写成字段,而是写的取值函数,这意味着你这段函数即时到了AccountType中你也无需修改,你只需要对AccountType增加对应的取值函数interestRate()即可完成Move Method。

『重构--改善既有代码的设计』读书笔记----Move Field的更多相关文章

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

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

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

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

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

    在面向对象中,对于类这个概念我们应该有一个清晰的责任认识,就是每个类应该只有一个变化点,每个类的变化应该只受到单一的因素,即每个类应该只有一个明确的责任.当然了,说时容易做时难,很多人可能都会和我一样 ...

  4. 『重构--改善既有代码的设计』读书笔记----Inline Class

    如果某个类没有做太多的事情,你可以将这个类的所有特性搬移到另外一个类中,然后删除原类.可以看到,Inline Class正好和Extract Class相反,后者是将一个巨类分解成多个小类从而来分担责 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 安装完出现Deprecated: Function ereg_replace() is deprecated in

    php5.3说明   先不要用php5.3吧,毕竟目前版本要修改这个工作量太大,而且可能会有很多未知错误,这只能在下一版全部改用perl的正则了,都不明白php官方发 什么神经,此外不支持应该是直接屏 ...

  2. C# 使用Nlog记录日志到数据库 使用LogEventInfo类获取,命名空间名称、类名、方法名

    原文地址:http://dotnet.9sssd.com/csbase/art/793 [摘要]Nlog是一个很不错的.NET日志记录组件,它可以将日志输出到控件台,保存到文本,也可以很方便的记录到数 ...

  3. [Java] JavaMail 发送带图片的 html 格式的邮件

    JavaMail 发送的邮件正文和附件是相互独立的,但是内置图片需要定位图片在正文中的位置,所以内置图片和邮件正文是互相依赖的. 发送带附件的邮件可参考JavaMail 发送 html 格式.带附件的 ...

  4. hdu1026 Ignatius and the Princess I (优先队列 BFS)

    Problem Description The Princess has been abducted by the BEelzebub feng5166, our hero Ignatius has ...

  5. CSS3动画变形Animations

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. Android中的FrameLayout帧布局

    帧布局由FrameLayout所代表,FrameLayout直接继承了ViewGoup组件. 帧布局容器为每一个增加当中的组件创建一个空白的区域(称为一个帧),每一个子组件占领一帧,这些帧都会依据gr ...

  7. 分享一个牛逼的PHP无限极分类生成树方法,巧用引用(转)

    你还在用浪费时间又浪费内存的递归遍历无限极分类吗,看了该篇文章,我觉得你应该换换了.这是我在OSChina上看到的一段非常精简的PHP无限极分类生成树方法,巧在引用,整理分享了. function g ...

  8. MySQL的优化点总结---通过计算多种状态的百分比看MySQL的性能情况

    1 读写比例: show global status like 'com_select';  获得服务器启动到目前查询操作执行的次数:show global status like 'com_inse ...

  9. 用 Qt 中的 QDomDocument类 处理 XML 文件(上)

      我们可以看到,如果所要读取的XML文件不是很大,采用DOM读取方法还是很便捷的,由于我用的也是DOM树读取的方法,所以,本文所介绍的也主要是基于DOM的方法读取. 根据常用的操作,我简单的把对XM ...

  10. spring mvc DispatcherServlet详解之拾忆工具类utils

    DispatcherServlet的静态初始化 /** * Name of the class path resource (relative to the DispatcherServlet cla ...