|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: 2017编程提高第2节课——面向对象设计(2) |
| 4 | +date: 2017-06-18 16:03 |
| 5 | +categories: 2017编程提高 |
| 6 | +tags: [软件工程,面向对象设计,课件] |
| 7 | +--- |
| 8 | + |
| 9 | +* content |
| 10 | +{:toc} |
| 11 | + |
| 12 | +# 面向对象设计的原则 |
| 13 | +- 单一职责原则 (SRP) |
| 14 | +- 开闭原则 (OCP) |
| 15 | +- Liskov 替换原则 (LSP) |
| 16 | +- 接口隔离原则 (ISP) |
| 17 | +- 依赖倒置原则 (DIP) |
| 18 | + |
| 19 | +- SOLID |
| 20 | + |
| 21 | +# 开闭原则(OCP) |
| 22 | +可复用的“基石” |
| 23 | +- 软件模块对扩展是开放的 |
| 24 | + - 当需求发生改变时,可以对模块进行扩展 |
| 25 | +- 软件模块对修改是封闭的 |
| 26 | + - 对模块进行扩展时, 无须改动模块的源代码。 |
| 27 | +- 似乎是矛盾的 ? |
| 28 | + |
| 29 | +![][1] |
| 30 | + |
| 31 | +![][2] |
| 32 | + |
| 33 | +## 缺点 |
| 34 | +- 对扩展开放: 可以添加新的水果类 |
| 35 | +- 但是每次添加新的水果类,就需要修改ShopCart中的逻辑 |
| 36 | + |
| 37 | +![][3] |
| 38 | + |
| 39 | +![][4] |
| 40 | + |
| 41 | +![][5] |
| 42 | + |
| 43 | +## 修改后 |
| 44 | +- 对扩展开放 |
| 45 | + - 可以任意的添加新的水果类:香蕉,西瓜… |
| 46 | + - 对修改是封闭的 |
| 47 | +- 对于ShopCart中的计算逻辑不用修改。 |
| 48 | +- **关键是抽象 !** |
| 49 | + |
| 50 | +*开闭原则的关键在于抽象出一个概念,然后针对接口编程,但是不要过度抽象,抽象到一定合适的层次即可 |
| 51 | +继承和多态都是OCP的一种具体的实现方式* |
| 52 | +## 三分钟练习 |
| 53 | +![][6] |
| 54 | + |
| 55 | +![][7] |
| 56 | + |
| 57 | +![][8] |
| 58 | + |
| 59 | +简单的答案 |
| 60 | +```java |
| 61 | +public class Employee{ |
| 62 | + abstract void work(); |
| 63 | +} |
| 64 | +``` |
| 65 | +# Liskov替换原则(LSP) |
| 66 | +子类型能够**完全**替换父类型,而不会让调用父类型的客户程序从行为上有任何改变 |
| 67 | +**难道多态不就是为了达到这个目标吗?** |
| 68 | +## 正方形 is a 长方形? |
| 69 | +![][9] |
| 70 | + |
| 71 | +![][10] |
| 72 | + |
| 73 | +![][11] |
| 74 | +*违反了替换原则,如果在testArea方法中传入了Square对象,那么结果将会是16,即使两个set方法调换,结果也是25,不会等于20,这就有了矛盾,这是因为长方形默认隐含了隐藏的客观条件——长宽独立变化,不互相影响* |
| 75 | +## 鸟都会飞吗 |
| 76 | +![][12] |
| 77 | +### 某个程序员创建了一个鸵鸟类 |
| 78 | +![][13] |
| 79 | + |
| 80 | +![][14] |
| 81 | +processAll是运行良好的代码,由于鸵鸟类的加入, 变得岌岌可危了。 |
| 82 | +由于新加入鸵鸟(Ostrich)类,方法就会出错 |
| 83 | + |
| 84 | +![][15] |
| 85 | +非常恶心的方法: 明明是传进来的是父类Bird, 还得单独对鸵鸟这个子类做判断! |
| 86 | +产生Bug 的一大源泉! |
| 87 | + |
| 88 | +*解决鸵鸟问题的简单方式就是建立“飞行”接口,让可以飞的鸟实现飞行接口即可* |
| 89 | +## 小结 |
| 90 | +- 继承的目的 |
| 91 | + - 重用父类的代码 |
| 92 | + - 更重要的是, 复用那些使用父类的代码(例如processAll)!! |
| 93 | +- LSP实际上是确保我们做的抽象不会被子类破坏 |
| 94 | + |
| 95 | +*如果我们发现了程序被某个不安分守己的子类破坏了,那么首先就考虑替换原则被违反了,就考虑使用组合来代替继承* |
| 96 | +## LSP和契约式设计 |
| 97 | +Bertrand Meyer 在 1988 年阐述了 LSP 原则与契约式设计之间的关系。使用契约式设计,类中的方法需要声明前置条件和后置条件。前置条件为真,则方法才能被执行。而在方法调用完成之前,方法本身将确保后置条件也成立。 |
| 98 | + |
| 99 | +- Rectangle.setWidth的后置条件 |
| 100 | + - Assert (( width==w ) && (height == old.height)) |
| 101 | + *w为传进的参数,old表示老对象/先前的对象* |
| 102 | + - 很明显, Square 违反了这个后置条件 |
| 103 | + |
| 104 | +*虽然契约式设计好像很厉害的样子,但是因为后置条件在复杂的情况下非常难设计,所以往往被放弃* |
| 105 | + |
| 106 | +- 当通过基类(父类)的接口使用对象时, 用户只知道基类的前置条件和后置条件 |
| 107 | +- 派生类(子类) 只能使用相等或者更弱的前置条件类替换父类的前置条件 |
| 108 | +- 派生类(子类)只能使用相等或者更强的后置条件来替换父类的后置条件 |
| 109 | + |
| 110 | +# 接口隔离原则(ISP) |
| 111 | +- 客户端不应该依赖它不需要的接口 |
| 112 | +- 类间的依赖关系应该建立在最小的接口上 |
| 113 | + - 使用多个专门的接口比使用单一的总接口要好。 |
| 114 | +- 防止接口污染 |
| 115 | + |
| 116 | +## ATM例子 |
| 117 | +*实线为继承,虚线为实现* |
| 118 | + |
| 119 | +![][16] |
| 120 | + |
| 121 | +![][17] |
| 122 | + |
| 123 | +## 三分钟练习: 咖啡机 |
| 124 | +![][18] |
| 125 | + |
| 126 | +![][19] |
| 127 | + |
| 128 | +![][20] |
| 129 | +**有什么问题?** |
| 130 | + |
| 131 | +# 依赖倒置原则(DIP) |
| 132 | +- 高层模块不应该依赖于低层模块,二者都应该依赖于抽象 |
| 133 | +- 结构化编程: 高层依赖于底层 |
| 134 | + |
| 135 | +![][21] |
| 136 | + |
| 137 | +*框架对抽象概念进行操作* |
| 138 | + |
| 139 | +![][22] |
| 140 | + |
| 141 | +## 熔炉的例子 |
| 142 | +![][23] |
| 143 | + |
| 144 | +![][24] |
| 145 | + |
| 146 | +*改进后的代码中的`h`和`t`都是对温度调节器和控温器的抽象,实际上换成任意型号都可以,而不是局限于一个型号,这就是抽象,从代码中找出抽象的概念,然后让代码对抽象进行操作* |
| 147 | + |
| 148 | +![][25] |
| 149 | + |
| 150 | +## 三分钟练习 |
| 151 | +![][26] |
| 152 | + |
| 153 | +# 作业 |
| 154 | +重构该程序,使其符合OCP |
| 155 | + |
| 156 | +![][27] |
| 157 | + |
| 158 | +![][28] |
| 159 | + |
| 160 | + |
| 161 | + [1]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%871.png "开闭原则1" |
| 162 | + [2]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%872.png "开闭原则2" |
| 163 | + [3]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%873.png "开闭原则3" |
| 164 | + [4]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%874.png "开闭原则4" |
| 165 | + [5]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%875.png "开闭原则5" |
| 166 | + [6]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%876.png "练习1" |
| 167 | + [7]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%877.png "练习2" |
| 168 | + [8]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%878.png "练习3" |
| 169 | + [9]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%879.png "正方形 is a 长方形1" |
| 170 | + [10]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8710.png "正方形 is a 长方形2" |
| 171 | + [11]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8711.png "正方形 is a 长方形3" |
| 172 | + [12]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8712.png "鸟都会飞吗" |
| 173 | + [13]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8713.png "鸵鸟" |
| 174 | + [14]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8714.png "鸵鸟代码1" |
| 175 | + [15]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8715.png "鸵鸟代码2" |
| 176 | + [16]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8716.png "ATM1" |
| 177 | + [17]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8717.png "ATM2" |
| 178 | + [18]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8718.png "咖啡机1" |
| 179 | + [19]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8719.png "咖啡机2" |
| 180 | + [20]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8720.png "咖啡机3" |
| 181 | + [21]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8721.png "DIP" |
| 182 | + [22]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8722.png "DIP" |
| 183 | + [23]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8723.png "熔炉1" |
| 184 | + [24]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8724.png "熔炉2" |
| 185 | + [25]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8725.png "熔炉3" |
| 186 | + [26]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8726.png "练习" |
| 187 | + [27]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8727.png "OCP作业" |
| 188 | + [28]: https://www.github.com/lanyuanxiaoyao/GitGallery/raw/master/%E5%9B%BE%E7%89%8728.png "OCP作业" |
0 commit comments