Re: [問題] template 做 strategy pattern的問題

作者: tinlans ( )   2016-09-09 01:23:36
※ 引述《Sirctal (母豬母豬 夜裡哭哭)》之銘言:
: 不好意思,小弟我衍伸出一些疑問。用Template實作Strategy Pattern是不是有點失
: 去他最大的好處?? 因為畢竟這個模式最大的賣點就是run time下可以一個介面變換
: 不同的演算法。那麼用template的用途是? 我為什麼不直接去call那個演算法的物件
: 就好了?? 還要透過你template再一層。 我看Gof的書上說Strategy Pattern還有另外一點
: ,就是你如果演算法有用到不想給人家知道的資料結構或是機密。那可以在用他包一層
: 。可是感覺不出來這樣就可以不讓人家看到耶...
: 以上問題懇請回答
: 謝謝
時間不早了,簡單說一下,因為好像真的很多人讀完書以後亂用然後卡住。
GoF 的範例大都是立足在動態多型的世界,用 template 實作是立足在靜態多型的世界。
這兩個世界的面向有決定性的不同之處。
動態多型:通常你的 user 就是 end-user,不會寫程式,只是使用你的程式。
靜態多型:通常用在 library 設計,你的 user 是 programmer,他們會寫程式。
換句話說,靈活性是不是要作用於 runtime,取決於你程式和 user 的類型。
回歸到 design 的初衷,就是在遇到需求改變時,能夠靈巧地去應對。
你不需要修改太多 code,甚至大部分的時候只要新增 code,不會動到已測試過的部分。
我一向反對 programmer 在學 OOAD 之前就先學 OO design pattern,就是怕有人搞錯。
沒有 design 的基礎,只是把 design pattern 的好處拿來當 coding 工具,容易錯亂。
runtime 可抽換的特性是來自於動態多型,而動態多型是大多數 OOPL 都有的特性。
這個特性並非來自 design pattern 本身,design pattern 的用意也非如此。
目前市面上的書看起來都沒在釐清這些觀念,所以常常讓讀到的人很混亂。
一旦你要探討靜態多型版的 design pattern,那你就要以 library 設計者的角度出發。
你的 user 就是使用你 library 的 programmer,需求來自於各個不同性質的 project。
在一個特定的 project 裡,通常也只會用到一兩種組合,而且不需要 runtime 切換。
你的世界觀要從只是完成眼前的 project,擴大成幫助不同人完成各種未知的 project。
我知道要把視角切過來會不太直覺,因為國內學術界跟業界都不太有機會實作 library。
如果讀過 Modern C++ Design 這本書,policy-based design 是很早就介紹的概念。
在後續的章節裡,作者幾乎每一章就會做出一個 library,並在章末彙整用法。
在這裡可以清楚看到作者提供各種 policy 給 programmer 去選擇,這些都是好例子。
所以這個抽換的概念,在靜態多型的世界裡是這樣去理解的,不知道會不會很難懂?
因為我實在是很懶得想去找範例或想範例,這樣發一篇就天亮了 XD
******
洗澡的時候想了一下,還是找個靜態多型的 library 來說明好了。
希望能很快解釋完。
拿 Boost.Multiprecision 這個 library 當例子,眾所皆知它可用在大數運算上。
http://www.boost.org/doc/libs/1_61_0/libs/multiprecision/doc/html/index.html
不知道怎麼用的話,在 Introduction 那邊有基本用法,我這只說明必要的部分。
簡單說,boost::multiprecision::number<> 可以宣告一個大數型別,
而在角括號裡可以選用後端的不同實作。
number<cpp_int_backend<>> 就是選擇 cpp_int 這個後端。
number<gmp_int> 就是選擇 gmp_int 這個後端。
整數類型可選擇的各種後端,在這裡有列出:
http://goo.gl/p3t6MZ
浮點數類型可選擇的各種後端,在這裡有列出:
http://goo.gl/8lZovH
我們拿整數類型可選的後端比較表來看,可以很快歸納出選擇者會有的考量,譬如:
1. 目前的這個專案是否與 GPL 或 LGPL 相容?
2. 目前這個專案是否除了和 boost libs 相依外,還要相依其它 libs?
3. 哪個實作可以有最快的執行速度?
在一個專案裡,基於這些考量的不同組合而得到的結論,通常也只會敲定一個。
譬如你覺得用什麼 license 都沒差,只是想要執行得快,那就會選 gmp_int。
如果你的專案跟 GPL 和 LGPL 都不相容,而 Boost 的 licesne 跟你專案沒有衝突,
又不希望專案多相依一個 libtommath,那你可能會選擇 cpp_int。
一旦你決定在這專案要用 cpp_int 的後端,你就不會想在 runtime 切成 gmp_int。
你的 user 並不特別在意你後端是什麼,你想讓他們選,還得先寫一堆文件教育他們。
如果只是開發一個普通又大眾化的應用程式,你並不需要在 runtime 切換後端。
因此,Boost.Multiprecision 在這部分被設計為使用靜態多型,而不是動態多型。
如果你的視角是在開發一個需要用到大數運算的程式,也熟 GMP,可能就直接用 GMP 了。
Boost.Multiprecision 的存在與否,為何如此設計,都跟你沒有什麼關係。
你也不可能因為要開發一個應用程式,就先開發一套像 Boost.Multiprecision 的 lib。
實際上這也是國內絕大多數 programmer 一生當中的視角,因為產業型態就是如此。
在學校為了交一個作業去開發出 Boost.Multiprecision,只會變成笑柄。
同學會說你學技術學到走火入魔,做一件簡單的事繞這麼大圈,別人早你十天就寫完了。
在公司,你只會被主管當成拖慢進度的麻煩人物,還可能被大家當成神經病。
我說這些並不是建議你應該繞遠路,只是在說沒什麼契機對多數人而言是相當正常的。
如果你真的因為這些理由去做一套,那我也會笑你,覺得你搞不清楚狀況。
那你可能會問,如果都沒使用靜態多型設計程式的契機,是不是就不必使用它了。
答案是肯定的。因為你沒有需求,沒有動用這項機制的理由,你就不該一直想著要用。
知道這項機制存在,並且概略知道原理,其實就很夠了。
事實上,在契機出現之前,悶是硬想要怎麼去運用一個機制,是很危險的心態。
這有點像小孩子拿到打火機,覺得打火機能點火很好玩,就四處找地方點火一樣。
你不知道,又勇於提出來問,找知道的人回答你,我覺得這點已經贏過很多人了。
實際上不管是靜態多型還是 template metaprogramming,在需求真正到來前,
事先學會或略懂的人常常只是為用而用,然後都用錯地方,反而讓程式很難維護。
比較正常的方向,應該是先想著要去解決某個問題,然後才去選擇適當的工具。
要反方向走的話,很容易變成拿打火機四處亂點火的小孩,成為令人頭痛的人物。
這十幾年間一直有一些玩火死小孩讓我很頭痛,所以有感而發,講了不少廢話 XD
可能和學校軟體設計的教育完全失敗,相關技術跟知識絕大多數人是自學這點有關。
然後學習資源斷層也是不小,基礎書籍之後,就是直接往一些很進階的主題跳。
design pattern 變成為了優越感而學,為了優越感而用,或者只是為了跟流行。
TMP 很突兀地出現在程式裡,問為什麼,結果說只是因為覺得這樣寫比較帥。
另一種答案是花了很多時間和心力去搞懂,懂了以後都沒地方用,就用用看。
還有就是因為會某種複雜設計的人很少,以後其他人很難接,這樣他的重要性會提升。
聽到這些奇奇怪怪的理由,我也只能跪了...
我這篇也留下了一個疑問:
「那到底什麼情境下會想去設計像是 Boost.Multiprecision 這樣的一個 library?」
這個問題我不打算幫你解答,你也不要在正式場合裡為了做這種東西而做。
因為在你第一次親身處於有此需求的情境之前,別人講什麼其實都很難真正去體會。
如果一生都沒有機會處在那種情境下,並不表示你就低人一等,只是選擇的路不同。
當然如果有一天你有機會處在那個情境裡,也歡迎你回板上跟大家分享你的心得。
一旦你有機會從事這類 library 的設計,不管是休閒還是工作,都會有很多體悟。
作者: CoNsTaR ((const *))   2016-09-09 02:29:00
推 又釐清觀念了
作者: johnny94 (32767)   2016-09-09 03:32:00
講得真好
作者: lovejomi (JOMI)   2016-09-09 06:12:00
請教一下 大數那段, 為什麼會扯到license呢,是因為我具現化不同backend所以專案 只會感染到那部分的程式碼以及license規範嗎
作者: descent (「雄辯是銀,沉默是金」)   2016-09-09 09:34:00
為用而用和因為努力學了這技巧而硬要使用這段,心有戚戚焉
作者: mabinogi805 (焚離)   2016-09-09 09:52:00
推心態~ 順便體悟心靈祥和(別
作者: hn12404988 (Willy)   2016-09-09 10:48:00
學習了
作者: BlazarArc (Midnight Sun)   2016-09-09 11:01:00
作者: legendmtg (CLANNAD)   2016-09-09 13:37:00
<(_ _)>
作者: Chikei ( )   2016-09-09 16:20:00
推心態,但是這心態跟DP一樣,沒撞過真的很難知道多重要XD
作者: bluesoul (忙死你老爸)   2016-09-09 19:45:00
design pattern不就是一種自然而然的東西嗎?他只是歸納出各種情境下會使用的適當架構為何還會有優越感或是造神
作者: CoNsTaR ((const *))   2016-09-09 20:15:00
樓上 你從來沒有感覺到 c++ 社群崇尚技術大於一切的風氣嗎不論是書籍還是網路 普遍看來都是這樣的吧…
作者: Sirctal (母豬母豬 夜裡哭哭)   2016-09-09 21:10:00
我很好奇 CoNsTaR大 可以推薦一下 C++的社群嗎??
作者: james732 (好人超)   2016-09-09 21:24:00
推心得分享,覺得自己也有犯過這種錯誤 Q_Q
作者: sa074463 (壘包)   2016-09-09 22:20:00
推,我寫不了厲害的只能寫普通的XD...
作者: bluesoul (忙死你老爸)   2016-09-09 22:33:00
看懂的人少是一個很危險的訊號,代表程式可讀性很差,偏偏這又是大型軟體相當重要的一環好的程式碼應該是易讀,易懂,好維護,好擴充,功能正確,沒有顯而易見的效率問題
作者: Sirctal (母豬母豬 夜裡哭哭)   2016-09-09 22:38:00
我覺得除非某些關鍵地方真的是效能大於一切而且不是很常變動的地方再來用這種技巧會比較好個人淺見
作者: CoNsTaR ((const *))   2016-09-09 23:08:00
沒有特別指什麼啦…只是泛指網路上的 c++ 使用者們而已
作者: EdisonX (卡卡獸)   2016-09-10 05:05:00
作者: chchwy (mat)   2016-09-10 08:19:00
推推
作者: Sidney0503 (Sidney0503)   2016-09-10 09:18:00
該loop就loop 該call就call這多難?甚麼時候是那個"該"別人的設計就算是迴圈和函數 有時候還是要問本人有的是說未來好增加功能 有的是說好替換...這種判斷要磨多久才能練成XD
作者: Clangpp (Clang++)   2016-09-10 11:36:00
感動 我現在就在拜讀 Modern C++ Design 只是想問說 他後來有沒有繼續出 C++14甚至C++17的版本??像C++ Templates: The Complete Guide作者已經預告要出C++17的版本了
作者: final01 (牛頓運動定律)   2016-09-10 15:48:00
t大完全是另一種境介了,我還停留在努力學很神氣的東西亂用的程度....這是必經之路?
作者: EdisonX (卡卡獸)   2016-09-10 21:22:00
@final01,總比什麼都不學莫名的神氣來得好多了。
作者: james732 (好人超)   2016-09-10 21:57:00
哇Template那本出C++17版我會想買
作者: Clangpp (Clang++)   2016-09-10 22:08:00
作者: ronin728 (浪人)   2016-09-14 10:19:00
很多學 C++ 的人都喜歡玩弄花招,蔚為風氣
作者: Sirctal (母豬母豬 夜裡哭哭)   2016-09-14 23:10:00
可是要看需求阿 如果需要就是要用啊XD就像很多飛行員喜歡賣弄飛行技巧 平時沒用 但是空戰來時搞不好就真的有用了

Links booklink

Contact Us: admin [ a t ] ucptt.com