為什麼這篇疊床架屋故事鄉民發文收入到精華區:因為在疊床架屋故事這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者oaz ()看板Soft_Job標題Re: [閒聊] OOP小評時間Thu Mar 5 15:...
疊床架屋故事 在 T I N G Instagram 的最讚貼文
2021-09-24 02:49:13
《 BenQ&Ting 邀請大家一起。玩藝術。》#送最新光學檯燈 #gifted . 7月初Ting很榮幸接受 @benq_taiwan BenQ總公司的邀請,體驗她們最新NEW! 光學升級版的「#MindDuo親子共讀檯燈」。經過兩個多月產品體驗後,我們全家人都很滿意! . 因此Ting也決定把...
這一系列下來,看到不少對 OOP 、重構有誤解的地方
一、要理解 OOP ,需要先知道「OOP 想解決的問題是什麼?」
先看整個程式設計的發展
一開始是機械語言、組合語言
再來是程序式語言,所以衍生了結構化編程、流程圖的出現
之後是物件導向,衍生了 UML
如果拿不適合的標準去評論 OOP,
某種程度上跟問「你為什麼要用 C 寫,組合語言不是比較快」沒什麼不同
OOP 想解決的問題是什麼?
當「軟體規模」很大時,需求變動造成軟體很大的修改,甚至引起很多的問題。
在這沒有認知到這個問題時,一些批評 OOP 的論點就很有問題
A.關於「疊床架屋」
舉例,常常會看到類似的程式:
void A() {
doSomething1();
B();
doSomething2();
}
void B() {
C();
}
void C() {
doForC();
}
在這個例子中, A() -> B() -> C() -> doForC();
但 B() 根本沒做什麼事,只是直接再呼叫 C() 而言
這根本是「疊床架屋」,為何不直接 A() -> C()? 甚至 A() -> doForC()?
這樣的說法未必是錯的,但是 OOP 有另外的考量
舉個例子,在 OOP 中可以「繼承」 C()
void C() {
doAnotherForC();
}
這樣一改,C() 的行為變了,但不影響 A() 的邏輯。
此外,也可以改寫 B() (改寫方法有很多,同樣繼承是一種方法)
void B() {
if(case1) {
C();
} else {
D()
}
}
如果不用 OOP() ,那寫法可能變成:
void A() {
doSomething1();
if(case1) {
doForC();
} else if(case2) {
D();
} else if() {
}
doSomething2();
}
整個 A() 的邏輯就變大、變複雜
甚至,當 case1, case2 的邏輯改變時(譬如加入新的資料型態),A() 都要跟著改。
說到這,就想到一個有趣的故事:
問:現在有水壺、瓦斯爐、水龍頭,水壺內沒有水,現在要燒一壺熱水,要怎麼做?
答:
1.打開水龍頭,將水壺裝滿水
2.將水壺放上瓦斯爐
3.開啟瓦斯爐
再問:如果有水壺、瓦斯爐、水龍頭,水壺內裝滿水,要燒一壺熱水,那要怎麼做?
一般人會回答:
1.將水壺放上瓦斯爐
2.開啟瓦斯爐
數學家會回答:
1.將水壺的水倒掉
2.回到上一題的解法
有注意到嗎?數學家的回答是充分用已知的解答來回答新的問題
儘管當你深入去研究時發現:要先倒掉水,再裝滿水,不就是白費工?
於是,你要說:OOP 是疊床架屋?
是的,它是,但是它有它要解決的問題(軟體規模大到一定程度),
所以疊床架屋,但是最主要的問題不是「疊床架屋」,而是「軟體規模大」
B. 關於將資料和程序放在一起
我個人覺得更精確的說法是:將「相關的」資料和程序放在一起
想像我們現在在蓋一間房子,有兩種可能:
I. 每間房有各自的家電用品,開關都在各自的房間
II. 每間房有各自的家電用品,開關都集中在某一間房
那麼,我們會蓋哪一種?
OOP 是認為:對於資料,只有跟他有關的程序才能接觸他。
不太確定你所謂的「資料和程序不要放在一起」會是什麼情形?
就像是 C ,也會把
public A() {
if(x > 5) {
//
} else if(x > 2) {
} else {
}
}
C. OOP 沒變法定量或定性嗎?未必
我自己的定義就是「能省下多少功」
二. 關於「重構」
有版友提到:重構感覺就是在鬧革命
這只能說,對「重構」是完全的誤解
首先,重構的粒度有大有小
小到改變數名稱,大到修改整個繼承體系乃至於重寫,都是重構
(甚至,我個人都覺得,排版、增加空行、修改註解也可以算是重構了)
重點在於:要在什麼時間點,選擇怎麼樣的粒度
如果在要出貨前,來個如修改整個繼承體系一樣的重構,那基本是弄錯重構的精神
我個人對「重構」的定義是:「有系統地」「改善」「既有軟體」
因此,「有系統地」是一個很大的重點。
題外話:
不要以為重構改只有改註解,就不會有問題
有時候註解也是會產生 bug,譬如下面這個例子,用 gcc 會出問題
http://ppt.cc/WA0v (預期會是 437 ,有 bug 時是 400)
================== comment_matters.cpp ==================
#include <stdio.h>
int compute(int n) {
// 加法
n+=3;
// 乘法
n*=4;
// 自己乘自己乘自己
n*=n;
// 最後再加上37,希望能成功
n+=37;
printf("The result: %d\n", n);
}
int main() {
compute(2);
}
================== comment_matters.cpp ==================
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.112.30.46
※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1425539540.A.BD7.html
當你遇到一堆有的沒有維護的問題,你就會知道什麼是一定程度了
用 gcc 或 Dev-C 試試看
不妨猜猜為什麼會如此 :)
事實上,把相關的資料和程序放在一起,這很常見
假設在用 C 寫大數。
通常也會寫成類似:
struct BigNum {
}
void addBigNum(BigNum&, BigNum&);
void multiplyBigNum(BigNum&, BigNum&);
然後將這些放在 big_num.h/big_num.cpp
這就是把相關的資料和程序
只是在 OOP 有更簡單的作法,就叫 class
※ 編輯: oaz (140.112.30.46), 03/05/2015 17:53:15