Skip to content

Commit 94a213e

Browse files
author
lanyuanxiaoyao
committed
修改文件: _posts/2017-06-18-ocp.md
1 parent 503381e commit 94a213e

File tree

1 file changed

+188
-0
lines changed

1 file changed

+188
-0
lines changed

_posts/2017-06-18-ocp.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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

Comments
 (0)