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