提示:文章
文章目录
文章目录
前言
前期疑问:
本文目标:
一、背景
最近
二、重构手法
2.1 以委托取代继承
以委托取代继承是指我们常常为了一时的便利而错误地在代码中使用到了继承机制 。我们知道,继承可以使得子类获得了父类的非私有方法、属性,而我们却正好是看中了这种无形中的便利而不正当地在逻辑上几乎不相关的类之间使用了继承,实质上这种为追求便利的继承是无意义的。
具体请看下面的代码。
CPP
// 重构前
class Sanitation {
public String washHands() {
return "Cleaned ...";
}
}
class Child extends Sanitation {
}
在这里,卫生设备 Sanitation 类(假设为水龙头)具有给人们洗手的方法 washHands() ,但是这里的 Child 类想要具有 washHands() 的方法,但是完全不可以像上面那样子去 extends Sanitation 类啊,这两个类之间完全没有一点支持继承的联系。为了打破我们这种无意义的继承,以及消除这种带来不良影响的便利,我们应该进行重构,利用委托来实现。
重构第一步,先保留 extends 关系,这样便于一点点地检测我们的重构是否出错,如下:
cpp
class Sanitation {
public String washHands() {
return "Cleaned ...";
}
}
// 重构是一小步一小步进行的,先保留 extends 关系
class Child extends Sanitation{
// 具有委托对象 Sanitation 的实例
private Sanitation sanitation;
public Child() {
// 为委托对象赋值为当前对象,
// 因为我们还保留了 extends 关系
this.sanitation = this;
}
public String washHands() {
// 这里使用委托获得 washHands() 方法
return (this.sanitation.washHands());
}
}
当我们编译发现没有错误时(这时还不能运行,会发生栈溢出!),立即将上面 Child 类中的extends 去掉,并记得将构造函数中的 this 引用改成真正的创建一个 Sanitation 对象。
重构第二步:
cpp
class Child {
// 具有委托对象 Sanitation 的实例
private Sanitation sanitation;
public Child() {
// 删除 extends 关系
this.sanitation = new Sanitation();
}
public String washHands() {
// 这里使用委托获得 washHands() 方法
return (this.sanitation.washHands());
}
}
至此,重构成功了!这才可以运行测试了。
小结:用委托取代这种"莫名其妙"的继承关系,是比较符合逻辑的。像 Child 和 Sanitation 两个类,根本就不是一个继承树上的,原先代码结构表现出来的也是毫无意义的。此外,个人认为,《重构》这本书上对于每个重构的步骤讲得比较详细,但是《31天重构》这本书的这一篇文章中的这个例子比《重构》中的似乎更合理些,因为这里的代码是用了一个逻辑上没有继承关系的例子,就想上文。
2.2 使用c++实现
尝试使用c++实现,下面进过自己调试后的代码
// Sanitation.h文件
cpp
#ifndef TESTPROJ_LOCAL_WITHOUT_LIBRARY_REFACTOR_H
#define TESTPROJ_LOCAL_WITHOUT_LIBRARY_REFACTOR_H
#include <iostream>
class Sanitation {
public:
std::string washHands() {
std::cout << "Cleaned ..." << std::endl;
return "Cleaned ...";
}
public:
int sanitationCount; // 这边假设子类不需要继承这些成员
};
class Child : public Sanitation {
};
class ChildReflactor : public Sanitation{
// 具有委托对象 Sanitation 的实例
private:
Sanitation* sanitation;
public:
ChildReflactor() {
// 为委托对象赋值为当前对象,
// 因为我们还保留了 extends 关系
this->sanitation = this;
}
public:
std::string washHands() {
// 这里使用委托获得 washHands() 方法
return (this->sanitation->washHands());
}
};
#endif //TESTPROJ_LOCAL_WITHOUT_LIBRARY_REFACTOR_H
// Sanitation.cpp文件
cpp
#include "sanitation.h"
int main()
{
Child child;
child.washHands();
ChildReflactor childReflactor;
childReflactor.washHands();
}
打印结果:
shell
Cleaned ...
Cleaned ...
在上述代码中,如果按照实例写成this.sanitation = this; 会报错,改成指针就行。查了下c++的this是指针。
而且上述代码运行时没有出现栈溢出的情况,不知道是不是因为我的Sanitation成员是指针。
三、
3.1
总结
未完待续