作者H45 (!H45)
看板OOAD
标题[Guideline] AVOID PREMATURE INHERITANCE
时间Tue Dec 4 19:53:29 2007
____________________
AVOID PREMATURE INHERITANCE
Inheritance needs time to evolve.
﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉
※ 节录自 Prefactoring 第 63 页
没事不要继承,继承需要很长的时间才会演化。 (此为不负责任翻译......)
在设计 Applet 的时候,为了切割图形、控制、模组会采用 MVC Pattern
这边的 MVC Pattern 是单纯指图形类别、控制类别、模组类别。
我下面所要描述的重点在控制类别,有很多人会把控制器写成下面这个样子:
if (第一个按钮被按下) {
做第一种事情();
} else if (第二个按钮被按下) {
做第二种事情();
} /* ... */ else if (第 n 个按钮被按下) {
做第 n 种事情();
}
如果有 n 个按钮,就有 n 个 if-else 要写。
更惨的是,如果有新的按钮或是新的事件要加入这段程式码又要被改写一次
这完全违背开闭原则 (Open-Close Principle)!
一个类别设计完之後,除了继承它或是使用它之外
不应该再度修改它内部的程式码!
当程式设计师发现一大串的 if-else 或是 switch-case
就应该联想到 Class Inheritance
利用类别的多型来取代难以阅读的 if-else 或 switch-case
可以让原来的程式码不会被修改的情况下,新增按钮或是事件到一个新的类别
开发需求所述的新功能!
举例而言 (JAVA):
public class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent actionEvent) {
final String command = actionEvent.getActionCommand();
if ("Load Image".equals(command)) {
this.loadImage();
} else if ("Histogram Equalization".equals(command)){
this.histogramEqualization();
} else if ("Mean Filter".equals(command)) {
this.meanFilter();
}
}
}
这三个 if-else 区块分别处理三种不同的按钮事件
分别是读影像、做直方图等化、以及做平均过滤。
还好只有三个 if-else 区块,一开始还没什麽大不了的
但是随着需求的改变,按钮愈来愈多,程式码会开始大量地成长
public class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent actionEvent) {
final String command = actionEvent.getActionCommand();
if ("Load Image".equals(command)) {
this.loadImage();
} else if ("Histogram Equalization".equals(command)){
this.histogramEqualization();
} else if ("Mean Filter".equals(command)) {
this.meanFilter();
} /* 想像这边以後有一大串 if-else 区块 */
}
}
这可不是开玩笑的,每次加一个按钮就要修改原来的程式码并不是一个好现象!
倒不如切割整个类别为多个小类别,实作同一个介面 ActionListener
public class LoadImageHandler implements ActionListener {
// ......
}
public class HistogramEqualization implements ActionListener {
// ......
}
public class MeanFilter implements ActionListener {
// ......
}
这样的话,每次要新增一个按钮或事件处理,就只要新增一个类别实作 ActionListener
不需要再修改原来的程式码了!符合开闭原则 (Open-Close Principle)
有人会问:「那原来的 if-else 到哪里去了?消失了吗?」
我会回答:「可以说它消失,也可以说它还存在。
if-else 确实不见了,它原本的功能散落在不同的 ActionListener 子类别
里。判断的机制仍然存在,只是现在改由设定按钮的控制器实体,而不再由
控制器自己判断要做哪一种动作了!」
有人续问:「判断的机制仍然存在?那有比较好吗?」
我会回答:「加入新按钮的时候,设定新按钮的控制器为新的控制器,
我们加入全新的类别不会更动原类别的任何程式码,
在物件设计的角度来看是比较好的。」
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.116.247.13
※ 编辑: H45 来自: 140.116.247.13 (12/04 19:56)
※ 编辑: H45 来自: 140.116.247.13 (12/04 19:56)
1F:推 PsMonkey:总觉得标题跟後半部文章没啥关系耶... 12/04 20:44
2F:推 godfat:btw, 这本书我想卖... 12/04 21:11
3F:推 H45:後半部文章是说明什麽是成熟的继承。 12/04 22:21
4F:推 H45:回二楼,我觉得这本书很难读,是有一点点想卖 XD 12/04 22:22
5F:→ godfat:我是觉得这本书有点罗唆,也没太多新颖之处,相较refactoring 12/05 00:28
6F:→ godfat:看到一半就懒得继续看下去了,以後大概也不会看 12/05 00:29
7F:推 H45:我和你的看法相反,觉得 Refactoring 有点罗唆,看到一半就懒 12/05 07:53
8F:推 H45:得读下去,倒是 Prefactoring 有很多令我玩味的点子... 12/05 07:54
9F:→ godfat:那真是太有趣了 XDXD 不过我觉得有个可能原因是, 12/05 16:32
10F:→ godfat:我看 ref.. 比 pref.. 早很多,时空上有不小的差异... 12/05 16:33
11F:推 H45:真有趣 XDXD 我也读 ref.. 比 pref.. 早很多,我觉得原因是, 12/05 16:35
12F:推 H45:我读的 ref.. 是中文版,而 pref.. 是英文版,读感差很多 12/05 16:37