《重构》学习笔记(09)-- 处理概括关系

概括关系(Generalization),就是平时所说的继承关系。继承是面向对象的语言的重要特性,如何高效科学的使用继承,是重构的关键课题之一。

Pull Up Field(字段上移)

重构前

重构后

如果各子类是分别开发的,或者是在重构过程中组合起来的。你常常会发现他们拥有重复特性,特别是字段更容易重复。这时候,使用字段上移,将重复字段归类到超类中去。
这种重构的做法为:

  • 针对待提升之字段,检查它们的所有被使用点,确认它们以同样的方式被使用。
  • 如果这些字段的名称不同,先将它们改名,使每一个名称都和你想为超类字段取得名称相同。
  • 编译,测试。
  • 在超类中新建一个字段。
  • 移除子类中的字段。
  • 编译,测试。
  • 考虑对超类的新建字段使用Self Encapsulate Field。

Pull Up Method(函数上移)

类似于字段上移,如果一个函数在各个子类中有完全相同的结果,那么将该函数移到超类中。


重构前

重构后

这种重构的做法:

  • 检查待提升函数,确定它们是完全一致的。
  • 如果待提升函数的签名不同,将那些签名都修改为你想要在超类中使用的签名。
  • 在超类中新建一个函数,将某一个待提升函数的代码复制到其中,做适当调整,然后编译。
  • 移除一个待提升的子类函数。
  • 编译,测试。
  • 逐一移除待提升的子类函数,直到只剩下超类的函数为止。每次移除之后都需要测试。
  • 观察该函数的调用者,看看是否可以改为使用超类类型的对象。

Pull Up Constructor Body(构造函数本体上移)

你再各个子类中拥有一些构造函数,它们的本体几乎完全一致。在超类中新建一个构造函数,并在子类构造函数中调用它。

class Manager extends Employee ...
  public Manager(String name,String id,int grade){
     _name = name;
    _id = id;
    _grade = grade;
}

重构为

public Manager(String name,String id,int grade){
   super(name,id); 
   _grade = grade;
}

这种重构方法的做法

  • 在超类中定义一个构造函数。
  • 将子类构造函数中的共同代码搬移到超类构造函数中。
  • 将子类构造函数中的共同代码删掉,该而调用新建的超类构造函数。
  • 编译,测试。

Pull Down Method(函数下移)

如果超类中某个函数只与部分(而非全部)子类有关。将这个函数移到相关的那些子类去。


重构前

重构后

做法

  • 在子类中声明该函数,将超类中的函数本体复制到每一个子类函数中。
  • 删除超类中的函数。
  • 编译,测试。
  • 将该函数从所有不需要它的那些子类中删掉。
  • 编译,测试。

Pull Down Field(字段下移)

超类中某个字段只与部分(而非全部)子类用到。将这个字段移到需要它的那些子类去。


重构前

重构后

做法

  • 在所有子类中声明该字段。
  • 将该字段从超类中移除。
  • 编译,测试。
  • 将该字段从所有不需要它的那些子类中删掉。
  • 编译,测试。

Extract Subclass(提炼子类)

类中的某些特性只被某些(而非全部)实例用到。新建一个子类,将上面所说的那一部分特性移到子类中。


重构前

重构后

做法

  • 为源类定义一个新的子类。
  • 为这个新的子类提供构造函数。
  • 找出调用超类构造函数的所有地点。如果它们需要的是新建的子类,令它们改而调用新构造函数。
  • 逐一使用Push Down Method和Push Down Field将源类的特性移到子类去。
  • 找出所有这样的字段:它们所传达的信息如今可由继承体系自身传达(这一类字段通常是boolean变量或;类型码)。以SelfEncapsulate Field避免直接使用这些字段,然后将它们的取值函数替换为多态常量函数。所有使用这些字段的地方都应该以Replace Conditional with Polymorphism重构。
  • 每次下移之后,编译并测试。

Extract Superclass(提炼超类)

两个类有相似特性。为这两个类建立一个超类,将相同特性移至超类。


重构前

重构后

做法

  • 为原本的类新建一个空白的抽象超类。
  • 运用Pull Up Field、Pull Up Method和Pull Up Constructor Body逐一将子类的共同元素上移到超类。
  • 每次上移后,编译并测试。
  • 检查留在子类中的函数,看它们是否还有共通成分。如果有,可以使用Extract Method将共通部分再提炼出来,然后使用Pull Up Method将提炼出的函数上移到超类。如果各个子类中某个函数的整体流程很相似,你也许可以使用Form Template Method。
  • 将所有共通元素上移到超类之后,检查之类的所有用户。如果它们只使用共同接口,你就可以把它们请求的对象类型改为超类。

Extract Interface(提炼接口)

若干客户使用类接口中的同一子集,或者两个类的接口有部分相同。将相同的子集提炼到一个独立接口中。


重构前

重构后

做法

  • 新建一个空接口。
  • 在接口中声明待提炼类的共通操作。
  • 让相关的类实现上述接口。
  • 调整客户端的类型声明,令其使用该接口。

Collapse Hierarchy(折叠继承体系)

超类和子类之间无太大区别。将它们合为一体。


重构前

重构后

做法

  • 选择你想移除的类:是超类还是子类?
  • 使用Pull Up Field和Pull Up Method,或者Pull Down Method和Push Down Field,把想要移除的类的所有行为和数据搬移到另一个类。
  • 每次移动后,编译并测试。
  • 调整即将被移除的那个类的所有引用点,令它们改而引用合并后留下的类。这个动作将会影响变量的声明、参数的类型以及构造函数。
  • 移除我们的目标:此时的它应该已经成为一个空类。
  • 编译,测试。

Form TemPlate Method(塑造模板函数)

你有一些子类,其中相应的某些函数以相同的执行顺序执行类似的操作,但各个操作的细节上有所不同。将这些操作分别放进独立函数中,并保持它们都有相同的签名,于是原函数也就变得相同了。然后将原函数上移至超类。


重构前

重构后

做法

  • 在各个子类中分解目标函数,使分解后的各个函数要不完全相同,要不完全不同。
  • 运用Pull Up Method将各子类内完全相同的函数上移至超类。
  • 对于那些完全不同的函数,实施Rename Method,使这些函数的签名完全相同。
  • 修改上述所有签名后,编译并测试。
  • 运用Pull Up Method将所有原函数逐一上移至超类。在超类中将那些代表不同操作的函数定义为抽象函数。
  • 编译,测试。
  • 移除其他子类中的原函数,每删除一个,编译并测试。

Replace Inheritance with Delegation(以委托取代继承)

某个子类只使用超类接口中的一部分。或是根本不需要继承而来的数据。在子类中新建一个字段用以保存超类,调整子类函数,令它改而委托超类;然后去掉两者之间的继承关系。

重构前

重构后

做法

  • 在子类中新建一个字段,使其引用超类的一个实例,并 将它初始化为this。
  • 修改子类内的所有函数,让它们不再使用超类,转而使用上述那个受托字段。每次修改后,编译并测试。
  • 去除两个类之间的继承关系,新建一个受托类的对象赋给受托字段。
  • 针对客户端所用的每一个超类函数,为它添加一个简单的委托函数。
  • 编译,测试。

Replace Delegation with Inheritance(以继承取代委托)

你在两个类之间使用委托关系,并经常为整个接口编写许多极简单的委托关系。


重构前

重构后

做法

  • 让委托端成为受托端的一个子类。
  • 编译。
  • 将受托字段设为该字段所处对象本身。
  • 去掉简单的委托函数。
  • 编译并测试。
  • 将所有其他涉及委托关系的代码,改为调用对象本身。
  • 移除受托字段。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,321评论 6 543
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,559评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,442评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,835评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,581评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,922评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,931评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,096评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,639评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,374评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,591评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,104评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,789评论 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,196评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,524评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,322评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,554评论 2 379

推荐阅读更多精彩内容