《重构》读书笔记(八)——第八章 重新组织数据

 

1、自封装字段(Self Encapsulate Field)P171自封装字段

       在“字段访问方式”这个问题上,一直有两种截然不同的观点:其中一派认为,在这个字段所在的类中,你可以自由访问它;另一派则认为,即使在这个类中你也应该只使用设值/取值函数间接访问。

       两种方式,自有优缺点:

        1)间接访问变量的好处是,子类可以通过覆写(基类的)一个函数而改变获取数据的途径。

        2)直接访问变量的好处是,代码比较容易阅读。

       通常,我会使用直接访问方式,直到这个方式给我带来麻烦,此时我会使用Self Encapsulate Field,重构至使用间接访问方式。

       如果你想访问基类中的一个字段,却又想在子类中将对这个变量的访问改为一个计算后的值,这是最该使用 Self Encapsulate Field 的时候。

       一般说来,设值函数被认为应该在对象创建后才使用,所以在构造函数的初始化中应避免使用设值函数。这种情况下,要不在构造函数中直接访问字段,要不就是单独再建立一个初始化函数initialize(...)(根据需要选择是否需要参数)。

2、以对象取代数据值(Replace Data Value With Object)P175以对象取代数据值

      开发初期,你往往决定以简单的数据项表示简单的情况。但是,随着开发的进行,你可能很快会发现,这些简单的数据项不再那么简单了。这个数据项通常要与其他数据和行为一起使用才有意义。这个时候我们应该将该数据项变成对象(Replace Data Value With Object)。

3、将值对象改为引用对象(Change Value to Reference)P179将值对象改变为引用对象

     首先,使用Replace Constructor With Factory Method. 对于引用对象的创建,有两种方式:预先创建好或者引用时再创建(延迟创建)。不管采用哪种方式,都应该采用“字典(map)”保存引用对象的集合。

     在应用程序启动时,预先将这些引用对象加载妥当(可以通过配置文件或数据库或在代码中明确生成)。

4、以对象取代数组(Replace Array With Object)P186以对象取代数组

5、复制被监视的数据(Duplicate Observed Data) P189复制“被监视数据”

       一个分层良好的系统,应该将处理“用户界面”和处理“业务逻辑”的代码分开。这样做的好处很多:1)如果用户界面代码同时承担两种责任,用户界面会变得过分复杂,从而增加修改和维护的难度;2)与GUI隔离之后,领域对象的维护和演化都会更容易,我们甚至可以让不同的开发者负责不同部分的开发。

       建立一个领域类,并在展现类中为其建立一个字段。

      本重构的任务就是将与展现无关的计算逻辑从GUI类中分离出来。其主要手段就是保持领域类对象的数据与GUI类的数据同步,并从领域类的数据来更新GUI界面。

       这是一项非常有意义的重构,我们平常的项目中,很多时候讲计算逻辑代码放到GUI代码中,导致很多累赘类,冗长类,巨大类,给修改和维护造成很大的困难。

       // 观察者模式(Observer)

6、以字面常量取代魔法数(Replace Magic Number With Symbolic Constant)P204以字面常量取代魔法数

7、封装字段(Encapsulate Field)P206封装字段

      面向对象的首要原则就是封装,或称“数据隐藏”,也称“信息隐藏”。按此原则,我们绝不应该将数据声明为public。

      当然,通过Encapsulate Field只是封装过程的第一步,实施Encapsulate Field之后,我们应该尝试运用“Move Method”将使用这个字段的代码搬移到该字段的属主类中去。   

      在实际项目中,经常使用一些纯数据结构(类),用来组合一些相互有关联的数据字段值。这种情况下,我们从实用的角度出发,允许字段是public的,并用struct定义该(类)结构。

8、封装集合(Encapsulate Collection)P208封装集合

       如果类的一个字段为集合类型,则对这个集合的处理方式应该有所不同。取值函数不应该返回集合自身,因为这会让用户得以修改集合内容而集合拥有者却全然不知。也不应该为这个集合提供设置函数。替而代之应该提供为集合添加/移除元素的函数。只有在以下两种情况下才需要用到集合设置函数:

 1)集合为空时: 这时也应该用initializeXxxx()代替设置函数;

 2)准备将原有集合替换为另一个集合时:这时也应该用replaceXxx()代替设置函数。

       对于这项重构,C++与Java稍有不同,在C++中,我们不赞成返回类成员变量的引用,如果处于效率原因需要这样做时,也应该将返回值加以const修饰,以防用户代码修改类成员变量。如下所示:

        const vector<float> &getLogCurve() const;

        也就是说,如果不通过类提供的接口,谁也不能修改类的成员变量。

 9、以数据类取代记录(Replace Record With Data Class)P217以数据类取代记录

       起初这样的数据类通常会是一个“哑”对象,但是接下来的重构或许会为他添加行为(职责)。

10、以类取代类型码(Replace Type Code With Class)

       任何接受类型码作为参数的函数,所期望的实际上是一个数值,无法强制使用符号名,因此编译器不能对其实施类型检查。 本项重构体现了“以类表示概念”的思想。用于去除“基本类型偏执”代码坏味道。

11、以子类取代类型码(Replace Type Code With Subclasses)

       switch语句总不是一个好东西,我们应该总是避免使用switch语句。但只有一处用到了switch语句的代码还是可以接受的,并且还是在创建何种对象时。

12、以State/Strategy取代类型码(Replace Type Code With State/Strategy)

        本项重构与以子类取代类型码极为相似,但如果“类型码的值在对象创建后可能发生变化”或“某种原因导致宿主类不能被继承”,这种情况下可以使用本重构。

13、以字段取代子类(Replace Subclasses With Fields)P232以字段取代子类

        建立子类的目的,是为了增加新特性或变化其行为。继承是复杂的,也增加了子类与基类之间的耦合度。根据软件设计的“正确、简单和清晰第一”原则,如果一个子类中只有常量函数(返回不同的硬编码常量的函数),这样的子类实在没有存在的价值。因此,可以通过Replace Subclasses With Field移除这些无用的子类。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值