討論區快速選單
知識庫快速選單
掌握Salesforce雲端管理秘訣 軟體開發過程中有哪些資安漏洞?
[ 回上頁 ] [ 討論區發言規則 ]
Singleton container
更改我的閱讀文章字型大小
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/10/29 上午 02:00:03
接觸過singleton之後,發現singleton實在是很實用的pattern。
但是每次使用時都必須重複做一些瑣碎的宣告,總希望能寫成一個base class簡化設計,
可是研究過
<<Head First Design Pattern>>
<<Effective C++>>
<<More Effective C++>>
<<Modern C++ Design>>
這些書籍的singleton實作方式後,還是沒能得到一個完美的解法;target class總是必須改寫才能得到singleton的效果。
於是忽然想到另一個方法,將target class當作base class,由singleton反過來繼承target class。

這種反繼承的寫法,結果比較像是容器,
最大的特點就是不需改寫target class,因此並不強制要求target class建構式必須是private(事實上不能是private),
你仍然可以擁有多個target class instance,但Singleton<target class>就只能有唯一的instance。

自己試用了一陣子後發現還滿好用的,當你不需要singleton特性時可以自由的使用target class,但隨時可以將target class變成singleton。
甚至也可以做出Singleton<std::vector<target class> >這樣的事情。
於是繼續擴充,將<<Modern C++ Design>>中的policy概念引入,並實作出基本的policy。
也加入了SingletonManager解決release順序的問題,在此與大家分享。

其他特性:
•是一種phoenix singleton,release後可以重生
•若交由SingletonManager自動release,會依照建構完成的相反順序進行
•SingletonManager本身也是以Singleton<>實作
•create policy可指定生成方式使用new/delete或malloc/free
•thread policy可以double checked locking方式處理同步問題

當然這是發展中的版本,可能有些地方設計不夠周全,也沒有作任何最佳化。
其中mutex的部分請自行用適當的多緒函式庫提供的取代。
如果有任何問題或指正都歡迎提出討論,感謝。

範例與原始碼請參考以下轉貼

http://social.msdn.microsoft.com/Forums/zh-TW/234/thread/8e100105-cb25-49b3-9732-c77476efaeaa
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/1 下午 01:25:19
Singleton是OO初學者才會去用的東西。說好聽一點是Pattern,其實Singleton根本就是Global variable。花那麼多時間去思考如何實作,倒不如去想如何拿掉Singleton。
作者 : daniel(冷眼)討論區板主 VC++優秀好手遊戲程式設計優秀好手DirectX優秀好手C++優秀好手貼文超過1000則人氣指數超過70000點
[ 貼文 1564 | 人氣 84169 | 評價 6990 | 評價/貼文 4.47 | 送出評價 15 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/1 下午 11:11:05
其實還是不一樣的.. = =
1.載入後.分配的不同
2.執行前.初始化的不同
3.可以在配合其他模式
  就像 graphic singleton 是base class 他還有 directx graphic / opengl graphic
雖然是唯一並不代表.只有一種模式..

不過單純狀況下寫個static class 全部使用static 函數/變數來處理也可以
作者 : sleepyfish(愛睏魚) C#優秀好手C++優秀好手貼文超過500則
[ 貼文 524 | 人氣 0 | 評價 2890 | 評價/貼文 5.52 | 送出評價 13 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人d8231657註記此篇回應為很有道理 2009/11/2 上午 12:54:29
"Singleton根本就是Global variable" 這句話是很有問題的~~~~~

Singleton 的存在,有其意義,誠如 冷眼 所言,
Global variable 是在 compile 階段就完成定址了;若是需要共用的
東西,是以“物件”的形式在,而且是在執行階段才能決定該建構那個
物件,這時候,用 Singleton 會比建立一堆 object references,
然後在程式中判斷該用那個 reference 來得簡潔多了。
尤其在 OO 的精神中,本來就該適當的運用已經寫好的 class,你需
要用到的 class 的 properties / methods 不見得是 static
properties / methods,在沒 source code 可修改的情況下,也
不可能改成是 static ,這時 Singleton 就會是很好用的 pattern。

在適當的情況下,用適當的方法解決;整套 design pattern 能矻立
這麼久,自有其存在的價值。
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/2 上午 10:26:38
你們說的Singleton跟global variable不同點都著重在於compiler的角度,而我是以設計的角度出發。我以為我這點有說明得很清楚,既然有兩個人都看錯,應該是我的問題。

我大概列一下Singleton的問題好了(強調:從設計的角度!):
1. Tight coupling
用了Singleton的型別與Singleton機乎不可能分開,加上這個Singleton一定會被很多其它的型別用到。無形之中,所有用到Singleton的型別都會產生緊密的相依性,以至牽一髮動全身。

2. 不易做單元測試
因為型別直接使用了Singleton,單元測試就無法只測試單一個型別,而一定連Singleton都得一起測試。如果這個型別有修改到Singleton的狀態,就會影響到其它的單元測試,犯了單元測試的禁忌。

3. 「用 Singleton 會比建立一堆 object references...來得簡潔多了」
這正是最嚴重的問題之一!沒有了直接的reference,很難看出哪個class用到哪個class/interface。看起來很簡單的類別,也可以有複雜的相依性。比如這程式碼:
A *a = new A;
B *b = new B(a);
b->foo();
照道理說b->foo()最多只會影響到a,可是我常發現問題時,把B.cpp打開來看,才知道用了好幾個Singleton,使得B影響深遠。弄到後來其它一托拉庫不相干的型別也要去了解,所謂的"modularity"蕩然無存,更哪來的有"OO的精神"?
把reference藏起來就像是把垃圾掃到地毯下面的駝鳥心態一樣,表面看起來很"簡潔",實地上是亂七八糟。

4. 違反了Single Responsibility Principle
Singleton需要自己來建立、消滅,還要知道自己只能有一個。這是另一個responsibility。

5. 以前是Singleton,以後並不一定是
我在平常並不會特地去花時間把以前別人寫的舊程式碼裡的Singleton改掉,因為這實在是太麻煩了、太花時間了。加上有Singleton的程式通常都沒有單元測試,改了也不知道還能不能動。我的經驗是,後來都是因為遇到新的需求,才把Singleton改掉。印像最深(也最痛苦)的一次是到後來,連我認為最不可能的Logging都不能是Singleton了。神奇的是,改掉後整個系統的切割變得很明顯:不需要Log的,需要LogType1的,需要LogType2的都剛好有些以前沒發現到的相同性質,進而需要再一次的重構,之後架構變得更容易理解。

使用Singleton的問題與使用global variable會造成的問題機乎一模一樣。Singleton是好一點,又在Design Pattern裡面,所以大家誤以為這是個很好的設計,結果很多人把以前的global variable通通都換成Singleton就說這符合OO的精神。初學者看到Design Pattern,又看到這麼多的程式都充滿Singleton而跟著學。現在好像變成蟑螂一樣,動不動就會天外飛來一隻,怎麼殺都殺不死。在國外,Google甚至有自己開發一個程式叫Singleton Detector,被查到有Singleton的程式碼都不能checkin。

有很多可以取代Singleton的方法,最常用的就是直接傳入建構式。比如:
Singleton *s = new Singleton;
B *b = new B(s);

我想一定有人會說:可是如果我有一個類別要用十個Singleton,不就要:
B *b = new B(s1, s2, s3, ...., s10);
這太難看了吧?

沒錯!但這難看是因為去除Singleton能讓不好的設計無所盾形!遇到這樣的情形,該思考的是如何設計得更好:
- B是不是做太多事了?違反了Single Responsibility Principle?是不是該拆成更多個類別?
- 如果B對s1~s10每個都只用到一點點的功能,是不是s1~s10裡面的功能分類錯了?
- 是不是B根就就不該存在?該把B拆開後分到其它類別裡?
- 是不是s1~s10有些該合併,有些該拆開?
- 如果考慮其它的程式碼,還有更多更多的可能....

Singleton通常不會是那個「適當的方法」。Design Pattern更沒有所謂的"矻立不搖"。那是15年前的東西了,現在被廣泛運用後,有些Pattern都處在強烈的炮火之下,Singleton是第一陣亡的Pattern,只是你不知道而已。
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 上午 02:08:08
歐~~~想不到有人對singleton有那麼深的成見

先來探討一般的singleton。
沒錯,singleton的底層實作的確是利用global variable完成,但加上了妥善的包裝使其使用受到規範,使其被使用時可被追蹤並可封裝成物件。
另外從原始的設計角度來看,singleton的目的並不是為了全域存取,而是為了限制物件數量,全域存取只是附加效果而已。
不過也因為上述特性,我相信真的會有很多初學者濫用singleton(在此我並不強調pattern,我並不是design pattern的瘋狂信徒),
但那不是singleton的錯,singleton只是工具而已,端看你怎麼用它,更不應因噎廢食。
global variable也是一樣,雖易濫用,但仍有非它不可的時候,不是嗎?
當然人人心理都有一把尺,工具好不好用也是看個人,因此在這裡我並不想爭論singleton對與錯的問題,而是把焦點放在singleton的實作技巧,我分享我的研究的目的是希望大家來比較與傳統singleton做法的優劣和異同。

至於singleton container,
我想樓上各位應該都沒有看我分享的程式碼,甚至連我PO的原文也沒有仔細看吧?
因為各位的討論都是針對傳統singleton,而singleton container正是大大改善了魔王所提到的種種缺陷。
其中大部分都是從google Singleton Detector那篇來的吧?原文我看過了,姑且不提那是針對JAVA的論述,我並不熟JAVA,因此僅以C++為前提考慮其中提到的問題。
違反Single Responsibility Principle的問題有點太過理論...,傳統singleton或繼承式singleton甚至是loki singleton都有這個問題,必須自己管理物件或是至少必須定義private建構式,singleton container完全不必。
有時必須是singleton有時又不想的問題在singleton container中也不存在,因為base class根本不是singleton,完全不需改寫,懇請細細品味。

相依性的問題用傳入參考的方式並沒有減輕,仍然需要include才能使用,直接的使用本來就是必然相依;原文中另有提及間接使用,也就是使用base class指標,可以在test時使用不同版本。但這個問題根本不是singleton的問題,因為singleton仍然可以透過內含base class指標的方式選擇不同實作(我正好有實際愈過這個問題,詳細作法有點複雜,屬於singleton的進階應用,改日再分享)

singleton當然不是萬靈丹,但是絕對有適合它上場甚至非它不可的時機
(可曾想過在自訂的operator new function中如何建立global 物件,並保證在其他物件建立之前先完成?
singleton的使用時建構特性可以達成,但無法用傳入參考給new的方式解決),
雖然傳統做法有很多缺失,singleton container提供另一個方向,
千萬別讓部分缺點扼殺了後進學習的機會,萬幸。
歡迎並感謝各位賜教。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 下午 01:07:40
Singleton 把 global variable 隱藏了, 實在是
大大的一個隱患, 直接使用, 已經是迫不得已
的權宜之計, 你還為 隱患 再加上一層 厚厚的偽裝,
豈不是自找麻煩?

順帶一提, 你上文說到, 你的 Singleton container
可以使用 new 和 malloc(). 但是, 這是多餘.
我並沒有遇過 建立一個 C++ Object 時 (注意: 是一個)
用 malloc() 比較好 的情況.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 下午 01:35:15
你的 Singleton container, 大量使用了 multiple inheritances,
MACRO functions 和 MACRO statements 是另一大敗筆.

不論你寫什麼程式也好, 也應該盡量避免使用 MACRO.
而 inheritances 在 object 作 data members 不能達到需要
時才能使用 (例如 polymorphism).

還有, multiple inheritances 是任何情況也不應使用的.
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 下午 03:24:21
在這裡提供new/malloc的切換功能,其實只是提供架構,表示你可以輕易替換成任何第三方malloc函式,MallocCreator就當作是個example吧(其實在我實際應用的專案中因為需要避開new而有第三個特殊policy,因為是專用的此處沒有列出),另外<<Modern C++ Design>>原書中提供的版本也是有這個policy的。

multiple inheritances也是原書中Policy-Based class Design的重點,建議你參考原書。
macro在許多大型專案中用來切換debug/release實作是很常見的,此處是為了簡化singleton語法的一種syntax suger,並非必要的,如果你真的很討厭macro,
Singleton<TargetClass>::getSingleton().SomeFunction();
仍然可以工作,但可讀性差很多,反覆出現也很累人,因此我個人不認為是濫用macro。

==========================
題外話,用macro呼叫singleton有額外的好處,
singleton通常用於建立專案中唯一的子系統,例如log之類的,
如果將macro定成這樣
#ifdef DEBUG
#define LOG if(log_on) GS(LogSystem)
#else
#define LOG if(false) GS(LogSystem) //最佳化後什麼也不剩
#endif
就可以在debug時在runtime輕易選擇開關子系統不用重編,所有負擔幾乎消失僅剩下一個if,以利除錯、責任釐清之類的,
release時又可以強制關閉(或開啟)子系統。
我也曾經覺得macro沒什麼用,後來才學習到多采多姿的macro用法,static assert、new強制替換、runtime顯示define值、簡化inline assembly...等等
==========================

至於global variable之前提過了,跟multiple inheritances和macro一樣只是是否被濫用的問題,更何況singleton其實並沒有隱藏什麼,一樣需要include,辨識度並沒有比較差,反而可以控管存取管道(試想這在mutithread或debug時有多重要)。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 下午 04:04:30
關於為什麼不應該使用Multiple inheritances的討論, 很多很多年以前
已經原結了, 最簡單的原因, 是因為你可以用 single inheritance 取締它.
如果你堅持要去推翻這結論. 好的, 請便. 不過, 我相信沒有人會有興趣
去討論它了.

MACRO 是一架構鬆散的基制, 當然, 編程式就是解決問題, 靈活應變也
無不可, 不過, 當你為了 加強 data hiding / data encapsulation (...云云...)
而加入令人目眩神迷的 Singleton container 的同時, 居然使用另一
更嚴重地違反 data hiding / data encapsulation 等 原則的基制 ( 即 MACRO ).
本末倒置呢!!!

> 在這裡提供new/malloc的切換功能,其實只是提供架構,表示你可以輕易
> 替換成任何第三方 malloc函式,MallocCreator就當作是個example吧(其實
> 在我實際應用的專案中因為需要避開new而有第三個特殊policy,因為是專用的此處沒有列出),
> 另外<<Modern C++ Design>>原書中提供的版本也是有這個policy的。

這麼 你的程式的 new/malloc() 的切換, 就是多餘呀. 我不太清楚你所說的
情況, 不過, 大概也是因為設計不良, 所以才會出現你所說的 "第三個特殊" 情況吧.
書中說過, 又如何呢? 書中說的時候, 大概針對某情況去說呀, 你不可以這樣
斷章取義的. 還有, "書" 並不是一定正確.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/23 下午 04:22:15
> ... 更何況singleton其實並沒有隱藏什麼,一樣需要include,
> 辨識度並沒有比較差,反而可以控管存取管道(試想這在mutithread或
> debug時有多重要)。

singleton 之內, 包含了一 static private variable (即 global variable
under the specified class name).

global variable 的潛在問題, 我想, C++編程人員們 都應該有深入的了解.
但是, 隱藏在 class name 之內的 global variable, 當然是看不到, 但是
global variable 的潛在問題依然呀. 這樣不叫作 隱藏, 甚樣才算是 隱藏 呢?

隱藏了已經不妥, 不過, singleton 的話, 查看 header file 還是可以被發現的,
你的 Singleton container 呢, 是 隱藏+隱藏, 查看 header file 也看不到了.
情況之惡劣呀, 可比 static local variable 呢.
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 上午 10:35:26
你說你的程式解決了我提出Singleton的種種缺陷,我們可以一一檢驗是否屬實

1. 違反了Single Responsibility Principle (SRP)
如果有一個class A,有另一個class B繼承了A。的確A可以符合SRP,但除非B是空的,你怎能說繼承了A的B仍然只做一件事?更別說你的B除了A外還又再繼承了另一個類別。你的程式只是用繼承做出另一個版本的A,而新的版本仍然做了二件以上的事。

2. Tight coupling, 不易做單元測試
假設我有個class A,有class M使用了Singleton A,如以下程式
class A { /* ... */ };

#define SA GS(A)

class M {
public:
int fun()
{
     int result = SA.doSomething();
     if (result % 4 == 0)
     return result / 4;
     else
return result / 2;
}
};

我想要為M::fun做單元測試,想把SA換掉成別的class A實體該怎麼做? 答案:跟用一般的Singleton一樣難。沒有因為用了你的程式就比較簡單。因為M與SA有很緊密的相連性。

3. 看不出reference
當我看到用fun的程式碼,如"M *m = new M(); int k = m->fun();" 我還是看不出來M有暗中用到A,如果有另一個class N也用到SA,我完全想不到m->fun();有可能會影響到n->foo();的結果。物件相依性還是被隱藏了起來,這部分也與一般的Singleton相同。

4. 以前是Singleton,以後並不一定是
今天如果我有class M, class N與很多其它class都使用了SA,但我後來決定A不可再是Singleton了,可能M所用的A必需是與N不同instance的A,那我還是要一一去把所有用到SA的地方改掉。這跟用一般的Singleton也一樣麻煩。


請問你說你解決了我提出的缺陷指的是哪一個缺陷?

我不是沒看你的程式,而是故意不去談你的實作設計,因為那只會模糊焦點。我寫程式前先想的,不是實作,也不是設計,而去想是這寫出來的東西到底有什麼價值。能更方便做出Singleton是一個值得追隨的目標嗎?我要表達的是,一個程式裡,可以有只有一個instance的類別,但不該用Singleton Pattern來實作。所以,你不該使用Singleton Pattern,更別說去做一個讓別人可以很快的做出Singleton的程式。也許有些地方使用Singleton Pattern合理,但多到需要你程式裡的"SingletonManager"就太離譜了。其它很多白老鼠大大說得已經很完美了。

不知道你哪裡覺得我或你看到的文章是在說Java,我提出的是個設計缺陷,用哪個語言關係不大。不只Google Singleton Detector那篇,網上已有成千上萬的文章在說為什麼Singleton不好及取代方案,只是剛好有些用Java來舉例,我之前的例子都是用C++,證明這些缺陷不僅僅適用於Java。

我與許多Google的工程師一樣非常注重單元測式,而使用Singleton的程式碼就是不易被測試,不難想像有些Google工程師也同樣地反對Singleton。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 上午 11:14:06
很抱歉,我並沒有仔細閱讀諸位大大的貼文細節,只了解到文章的正反表述。
沒辦法,年紀大了,眼睛容易疲累。呵呵呵...
看來,是乎又是一個和"應不應該使用goto"一樣的爭議。
我總喜歡用"天生我材必有用"來形容這樣的爭議。
濫用材料,必然有反對者所說缺點漫天飛揚;
適材適所的使用,劣材也會變良葯!
假設一個應用場合 Singleton 是一個好的解決方案,在沒有更好的方案,就去使用它,何仿?
一用就有反方所說的缺點暴露?就當它是治病良葯的副作用吧!
話說回來,那種編程素材沒有副作用?副作用控制在合理範圍,就變成程式員的責任了。

Singleton 的目的在保證一個程式中的某個類別只有單一實例。
舉個最容易想到的應用: Spooler。
看花博排隊進場,管理者會希望有個方法可以讓隊伍是唯一的一條線。
若是隊伍一分為二,二分為四...那就是混亂的開始了。這唯一的一條線就是在程式語言來說
就是 Singleton。
Singleton 的機制,保證了再差的程式員也不會讓排隊的一條線一分為二。
你可以不喜歡原始Singleton的設計,但只要你是要寫一個不讓隊伍不會一分為二的程式。
不管,你的作法是什麼,那都是Singleton(自製的)。
當然,你也可以說:我就是不寫 Spooler 的程式。
那我也沒話說了,但別人可能為了飯碗,還是得寫 Spooler 的程式^^



作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 12:07:42
幫coco做簡報吧:)

一個程式裡,可以有只有一個instance的類別(coco singleton的定義是指這個吧?),但不該用Singleton Pattern來實作。

與其用Singleton Pattern, 以下程式碼明顯指出entrance1 entrance2用了同一個spool。清楚明了。
class Spool {...};
class FlowerExpoEntrance {...};

Spool *s = new Spool();
FlowerExpoEntrance *entrance1 = new FlowerExpoEntrance(s);
FlowerExpoEntrance *entrance2 = new FlowerExpoEntrance(s);
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人d8231657註記此篇回應為很有道理 2010/11/24 下午 12:14:22
回到樓主的原問題吧:
>於是忽然想到另一個方法,將target class當作base class,
>由singleton反過來繼承target class。
>這種反繼承的寫法,結果比較像是容器,
>最大的特點就是不需改寫target class,因此並不強制要求target class
>建構式必須是private(事實上不能是private),
>你仍然可以擁有多個target class instance,但Singleton<target class>
>就只能有唯一的instance。
這樣的 target class 還算是 singleton 嗎?
如果不是,那麼Singleton<target class>也不是。
Singleton<target class>目的在防止產止多個targt class的實例。
但target class成了後門,可以產生多個實例。
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 12:48:06
用compiler來強制讓一個class只能有一個instance是很重要的一件事嗎?重要到值得犧牲程式的可測式性嗎?
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 12:53:27
>與其用Singleton Pattern, 以下程式碼明顯指出entrance1 entrance2用了同一個spool。清楚明了。
>class Spool {...};
>class FlowerExpoEntrance {...};
>Spool *s = new Spool();
>FlowerExpoEntrance *entrance1 = new FlowerExpoEntrance(s);
>FlowerExpoEntrance *entrance2 = new FlowerExpoEntrance(s);
我並不是說singleton的不可取代性,而是說凡事適材適用。核先敘明 ^^
對於你舉的例子,只能"要求"(不能禁止)程式只產生一個spool;
但singleton的目的是,"禁止"程式產生第二個spool。
兩者的目的相同,但意義並不一樣。
是"要求"就夠了還是需要"禁止",要從應用程式的複雜度,參與程式員是一個還是多人等來評估。
這是我說的適材適所的意思(你的範例也是適材適所^^)。
另外一個我覺得失焦的地方是,singleton的目的是唯一性和存活期的保證,並不是它的全域性。
事實上,singleton的設計,也在避免全域性物件的性質。只是它的存活期,讓人覺得它是global物件。
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 01:03:44

>是'要求'就夠了還是需要'禁止',要從應用程式的複雜度,參與程式員是一個還是多人等來評估。

如果程式的複雜,或有很多人,是否單元測式為比較好的辦法?那為了'禁止'而失去testibility是值得的一個交換嗎?
作者 : sleepyfish(愛睏魚) C#優秀好手C++優秀好手貼文超過500則
[ 貼文 524 | 人氣 0 | 評價 2890 | 評價/貼文 5.52 | 送出評價 13 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 02:57:05
多吵無用,程式是用來開發工具的,用的人高興就好。
你說這個技術缺點很多,但還是有很多程式用它也從
無發生過問題;
你說它好,或許只是運氣好沒測試到而已。

重點在於程式員心中要明白所用技術的優缺點,並且如
何運用優點,避免缺點罷了。

如果真有完美的技術,到那一天,或許真的能 UML 拉
一拉時,就會自動把 code 全寫好了吧!!
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 03:05:54
>如果程式的複雜,或有很多人,是否單元測式為比較好的辦法?
>那為了'禁止'而失去testibility是值得的一個交換嗎?
我不敢也不能妄下定論。
而且好像也不能說,只要有testable,編譯期的檢驗機制就不需要。
老實說,我對你說的"失去testibility"並不是很明白。
相依性(或應該說關聯性)的問題,像你寫的那段:
>class Spool {...};
>class FlowerExpoEntrance {...};
>Spool *s = new Spool();
>FlowerExpoEntrance *entrance1 = new FlowerExpoEntrance(s);
>FlowerExpoEntrance *entrance2 = new FlowerExpoEntrance(s);
好像關聯性依然存在(沒有因避開了singleton而不見),這是因spooler的共用而引起的。
不論是不是singleton都一樣,是不是?關聯性程式的測試,只是比較需要下功夫,不是絕對無法測試。
反過來說,胡亂寫的程式,即使沒有關聯性作梗,也是難以測試。看起來"可測性"不是被singleton一刀
兩斷,一分為二。
不管那一種方法,若很注重程式的testable,事實上也都可以克服(就看值不值得付出代價);
就像一些需要singleton的場合,不用它還是可以用其它方法克服(但其它克服的方法,我認為還是
脫不了廣義的singleton)。

我承認,singleton和goto一樣,是不應該隨處可見的。
但遇到適合的場合,該用就用。不需要為了避開它而繞路。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 03:23:10
>重點在於程式員心中要明白所用技術的優缺點,並且如
>何運用優點,避免缺點罷了。
說得好!用什麼工具,不變的原則就是知道它的特點和應用的場合。
螺絲起子,就是用來鎖緊或鬆開螺絲的。
如果有人拿它來刷牙,覺得不好用,錯的不是螺絲起子。
如果有人拿它當武器傷人,還是不應該禁止製造螺絲起子。



>如果真有完美的技術,到那一天,或許真的能 UML 拉
>一拉時,就會自動把 code 全寫好了吧!!
我還要工作討飯吃,所以等我死後再說,可以嗎?
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 11:27:19

>關於為什麼不應該使用Multiple inheritances的討論, 很多很多年以前
>已經原結了, 最簡單的原因, 是因為你可以用 single inheritance 取締它.
>如果你堅持要去推翻這結論. 好的, 請便. 不過, 我相信沒有人會有興趣
>去討論它了.
我的確沒興趣在這討論這個,STL Boost Loki等等涵式庫都有善用多重繼承,iostream甚至用了惡名昭彰的鑽石型繼承

>MACRO 是一架構鬆散的基制, 當然, 編程式就是解決問題, 靈活應變也
>無不可, 不過, 當你為了 加強 data hiding / data encapsulation (...云云...)
>而加入令人目眩神迷的 Singleton container 的同時, 居然使用另一
>更嚴重地違反 data hiding / data encapsulation 等 原則的基制 ( 即 MACRO ).
>本末倒置呢!!!
說過了,macro在這只是簡單的文字替換,非必要,不是重點,效果只是讓你少打幾個字而已,我看不出跟data hiding / data encapsulation有什麼關係。還有傳統singleton也可以這麼用macro,其實跟singleton container沒有直接關係。

>> 在這裡提供new/malloc的切換功能,其實只是提供架構,表示你可以輕易
>> 替換成任何第三方 malloc函式,MallocCreator就當作是個example吧(其實
>> 在我實際應用的專案中因為需要避開new而有第三個特殊policy,因為是專用的此處沒有列出),
>> 另外<<Modern C++ Design>>原書中提供的版本也是有這個policy的。
>
>這麼 你的程式的 new/malloc() 的切換, 就是多餘呀. 我不太清楚你所說的
>情況, 不過, 大概也是因為設計不良, 所以才會出現你所說的 '第三個特殊' 情況吧.
>書中說過, 又如何呢? 書中說的時候, 大概針對某情況去說呀, 你不可以這樣
>斷章取義的. 還有, '書' 並不是一定正確.
>
哎呀呀,我有沒有斷章取義你至少該看過原作再評斷吧
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 11:48:31
>這樣不叫作 隱藏, 甚樣才算是 隱藏 呢?
這是我沒表達清楚,我所謂沒有隱藏甚麼的意思是,因為所有singleton幾乎都逃不過用static variable存指標這個手法,所以當你使用或看見singleton時就知道內部一定有static variable,既然眾所周知,就不算隱藏了。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/24 下午 11:52:40
d8231657(denny) 呀, 回應的意見實在是一面倒的,
你真的有必要繼續去為你的創作護航嗎? 或是說,
依你估計, 會不會有人帶你的原碼回去用呢?

(@@... 也許, 你是想為網友們留一個反面教材吧...
嗯嗯, 這樣就說得過去了...)
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/25 上午 01:08:35
>1. 違反了Single Responsibility Principle (SRP)
傳統singleton做法中,singleton程式碼是與target綁在同一個class,singleton container至少將它拆開到另一個template class之中,兩個獨立的功能已分別在不同class了。如果照你那麼說,豈不是所有用到繼承的class都違反SRP??

>2. Tight coupling, 不易做單元測試
>想把SA換掉成別的class A實體該怎麼做?
答案是我前面提過的進階用法,我曾經這樣做過:
class Interface
{ public: virtual someFunction()=0; }

class A:public Interface
{ public: virtual someFunction(){}; }

class B...//也實作Interface

enum TypeSelect
{ TypeA,TypeB }

class S
{
    Interface *p;
public:
    init(TypeSelect t)
    {
     switch(t)
     {
     case TypeA: p=new A; break;
     case TypeB: p=new B; break;
     }
    }
    Interface & operator->() //這裡我忘記是要回傳指標還是參考了,反正..就是那個意思
    { return *p; }
}
然後就可以這樣用
GS(S).init(TypeA); //可以在runtime選擇這次要用哪個實作
GS(S)->someFunction();
//這招傳統singleton也是可以用的
不知道這有沒有解決你說的test問題

>3. 看不出reference
>當我看到用fun的程式碼,如'M *m = new M(); int k = m->fun();' 我還是看不出來M有暗中用到A,如果有另一個class N也用到SA,我完全想不到m->fun();有可能會影響到n->foo();的結果。物件相依性還是被隱藏了起來,這部分也與一般的Singleton相同。
這個問題看不太懂???就算fun()中用的是new A;外面還是看不出來阿?另外fun()又如何影響foo()的結果?

>4. 以前是Singleton,以後並不一定是
我指的是,傳統singleton是就是,不是就不是,要改變就要改TargetClass,singleton container則可自由選擇,要用singleton時就寫GS(TargetClass).foo();,不想用時就寫Targetclass t;t.foo();,不用改TargetClass

>但多到需要你程式裡的'SingletonManager'就太離譜了。
SingletonManager存在的理由主要不是數量問題,而是可以保證多個singleton可以用建構完成的相反順序解構,因為singleton建構點取決於第一次使用,因此建構順序不確定,要保證解構順序正確傳統singleton很難做到
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/25 上午 01:12:04
> 而且好像也不能說,只要有testable,編譯期的檢驗機制就不需要。

大大有用過dynamically typed語言如Python, Ruby做過大型程式嗎?很明顯有很多人覺得程式只要testable,編譯期的檢驗機制不重要。以前當我只懂C++又不懂單元測試時也覺得編譯期的檢驗機制很重要。

>好像關聯性依然存在(沒有因避開了singleton而不見),這是因spooler的共用而引起的。不論是不是singleton都一樣,是不是?

是的。但可否請coco大大讀我第二篇第3點的內容,把關聯性藏起來是我的目的嗎?

>關聯性程式的測試,只是比較需要下功夫,不是絕對無法測試。

同意不是無法測試,但用了Singleton要"繞路"才能達成。且繞的路麻煩到沒有幾個人想去走,其它跟在後面的人也都會迷路。

>但遇到適合的場合,該用就用。不需要為了避開它而繞路。

也就是說用了Singleton才是繞路,避開它才是直線。

>螺絲起子,就是用來鎖緊或鬆開螺絲的。如果有人拿它來刷牙,覺得不好用,錯的不是螺絲起子。

如果比喻法能證明什麼,那我也需要一個。
用Singleton就像是用有鉛汽油,用我的方法就像是用無鉛汽油。兩者都可以達到相同的目的,但有鉛汽油就是硬生生地多了許多的汙染。如果有人拿有鉛汽油來洗澡,覺得不好用,錯的不是有鉛汽油。如果有人"正確的"用有鉛汽油來使用他的車子,造成很多鉛汙染,我也不怪有鉛汽油。我怪那個選擇不使用無鉛汽油的人。
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/25 上午 01:22:53

>這樣的 target class 還算是 singleton 嗎?
>如果不是,那麼Singleton<target class>也不是。
>Singleton<target class>目的在防止產止多個targt class的實例。
>但target class成了後門,可以產生多個實例。
的確,target class並不是singleton,因為當初就是希望可以不用修改target class直接套上singleton的功能才會這樣寫,而Sintleton<TargetClass>是不同的class,應該可以算吧(算不算不重要),總之,這套做法把要不要用singleton的選擇權留給了user,也許最後的結果變成全域存取和其他的性質重了點,限制物件數量反而沒那麼強制,這是singleton container的特性沒錯
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/25 上午 01:53:56
>> 這樣不叫作 隱藏, 甚樣才算是 隱藏 呢?
> 這是我沒表達清楚,我所謂沒有隱藏甚麼的意思是,因為所有
> singleton幾乎都逃不過用static variable存指標這個手法,所
> 以當你使用或看見singleton時就知道內部一定有static variable,
> 既然眾所周知,就不算隱藏了。

哎呀, 連 隱藏 的意思都要被 "重載" 了. 這樣按個人喜好把文字意思
肆意改變, 實在是不可取的. 這樣會對溝通構成極大的困擾呢.
名字, 只是代號, 用什麼稱呼本來就不重要, 重要的是它背後所代表的意思.
既然你堅持曲解 "隱藏" 的本意, 我不用這詞語, 直接描述情況呀.

Global variables, 在維護和開發程式時 需要特別地去照顧它們的.
假設我今天要把我的程式碼交給另一位同事, 我大概會對他說,

"同事呀, 程式裡有些 global variables. 要特別注意呀.”

如果我有用過 Singleton, 我就要再多說一句,

"某些 class 是 Singleton, 包含了一些 static private variables,
維護和開發的顧忌跟 global variables 類同的, 請務必把所有
include 了的 header files 和 這些 header files 的
header files 都搜查一次, 找出所有 static private variables,
然後特別特別地注意它們呀.”

如果我真的用了你的 Singleton container, 我就要再說,

"我有個 template class, 每使用這 template class 的時候,
都會生成更多 包含 static private variables 的 class 的,
請務必把所有原碼都搜查一次, 找出所有使用過
這個 template class 的指令, 然後特別特別特別地
這些 生成的class的 static private variables 呀.”


----------------------------------------------------


說到這裡, 應該已經是呼之欲出了, 使用 Singleton, 本來
已經是不方便維護了, 而你的 Singleton container 呢,
不僅是更加不方便維護, 更甚的是需要查看原碼才能發現的
 在 編譯時期生成的 class static private variables.
這某幾句包含 static private variables 的指令,
在茫茫原碼之內得到了十分好的掩護,
所謂 明槍易檔 暗箭難防, 遺漏的機會, 比 Singleton
高百倍呢.



PS: 一直要避開 "隱藏" 這個詞語作描述, 真的是好困難呢...
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人d8231657註記此篇回應為最佳解答 2010/11/25 下午 12:56:27
第一篇覆文,我就提出這是一個像"該不該使用goto"一樣的爭議。
反方永遠有理由,反對正方所提的意見;正方也永遠可以辯駁反方的論點。
這樣的爭議結果,通常是"誰也不能說服誰"。
那麼討論(比較不想用辯論)有義意嗎?
有!腦筋還是白紙的新人,可以從相關的討論中,消化成自己的觀點。
日後這觀點也會形成像"信仰"般的見解,別人再也無法說服他改變!
所以討論歸討論,就是別太認真的想"贏"。

>> 而且好像也不能說,只要有testable,編譯期的檢驗機制就不需要。
>大大有用過dynamically typed語言如Python, Ruby做過大型程式嗎?
>很明顯有很多人覺得程式只要testable,編譯期的檢驗機制不重要。
>以前當我只懂C++又不懂單元測試時也覺得編譯期的檢驗機制很重要。
直譯語言,沒有編譯器,怎麼比較啊!?
hmm...直譯器還是有一個parser,這可以視為編譯器的地位,它們還是有檢驗機制的。
至於重不重要,談下去不知道會不會,又是一個沒大輸贏的論戰?
很久以前,我上過IBM的軟體測試課程。課程大部份的內容大概都忘了,但第一堂課的
一句話,一直想忘也忘不了:沒有bug free的程式,也沒有可以找出所有問題的測試。
這句話不是引用聖經,所以不是上帝的話,但它提出一個對軟體測試應有的態度:
軟體測試是建立軟體可靠度的一個很好的工具,但不能忽略其它的檢驗機制。
程式有些問題可以很容易的在編譯時期找出來,但可能不容易測試得到。
我曾有多次經驗,維護一個運作很久的程式,發現某個成員應該是const屬性比較好。
把const加上去後,就引發了const的連鎖反應。編譯一直不過,有越改越多的感覺。
咬緊牙關,最後還是把它改完,過程竟發現非許可之下更改資料的問題。
當然你也可以說,這樣的問題可以如何的測試,就能發現,但這是事後諸葛。
任何完善的測試,永遠都有它不及之處!

>>好像關聯性依然存在(沒有因避開了singleton而不見),這是因spooler的共用而引起的。
>>不論是不是singleton都一樣,是不是?
>是的。但可否請coco大大讀我第二篇第3點的內容,把關聯性藏起來是我的目的嗎?
我只就關聯性引發的測試問題提出看法,"隱藏"的問題不是我要討論的。
"隱藏"的議題,我如果說"隱藏"有壞處(如你說的),但也有好處(封裝不就有隱藏的觀念嗎),是不是又會引發另一場
像"goto"的論戰?^^

>>關聯性程式的測試,只是比較需要下功夫,不是絕對無法測試。
>同意不是無法測試,但用了Singleton要"繞路"才能達成。
>且繞的路麻煩到沒有幾個人想去走,其它跟在後面的人也都會迷路。
如你也同意的,關聯性的問題不是只存在於singleton才會發生。
很多程式是避不開關聯性的問題,只能儘力少寫出像蜘蛛網般關聯程式;
singleton 在正方而言,也應是同意少用為妙,只是不認為該禁用。

>>但遇到適合的場合,該用就用。不需要為了避開它而繞路。
>也就是說用了Singleton才是繞路,避開它才是直線。
夷?怎麼順著我的話,轉成相反的意思 ^^

>>螺絲起子,就是用來鎖緊或鬆開螺絲的。如果有人拿它來刷牙,覺得不好用,錯的不是螺絲起子。
>如果比喻法能證明什麼,那我也需要一個。
>...恕刪...
有沒有像"鬆開螺絲"這樣的應用,適合使用"螺絲起子"(singleton)來解決的場合?
是不是爭議點?若是,那
如果能舉出一個應用例,使用singleton的好處是大於壞處的,那麼你是否可以同意
singleton可以解禁?
若答案是肯定的,我就想一個例子,不但適合singleton的應用,而且幾乎沒有你說的缺點的場合。
(有些缺點,並非singleton的必然)
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 上午 05:09:39
我完全沒有想要說服誰。剛看完Modern C++ Design與Design Patterns的denny是不可能被說服的(他提的書我全都看過) - 雖然他口頭上說「歡迎並感謝各位賜教」,行動上卻完全不是如此。硬要說誰,就說是十年前的我好了-那時的我跟denny一樣也是Singleton的愛用者:「嗯,這只能有一個實體,那就用Singleton Pattern!我用了書上所學的!漂亮!」。我想利用這個機會,整理一下我自己的思緒,把使用Singleton的缺點一一列出來。

我覺得就像蓋房子的人敢放心地偷工減料是因為他們日後不會住在那房子,很多的工程師就抱著反正以後又不是他來維護的心態來寫程式。寫完後收了錢就趕快拍拍屁股走人,維護是別人家的事。以至於Singleton這類在撰寫程式時很方便但不利於維護的設計被一面倒受到歡迎利用。

這麼方便的東西,不難想像在我提出質疑時,有大大忙著揮舞「Singleton還是有用處」的旗幟希望能「解禁」。

我想要的是激起讀者提出:「如果Singleton這麼糟糕,是不是時候該停止使用了?」「如果我把我程式裡的Singleton完全移除,那會發生什麼事?」「Singleton Pattern真的有存在的必要嗎?」「為什麼Google要完全禁止Singleton?」等問題。還是大家現在在業界看到的都是"Singleton被禁用"這個問題?

因單元測試是我反對Singleton的主因之一,有大半篇幅單元測試被受到攻擊。主要的攻擊點在於單元測試不能找出所有的bug,也不能證明程式沒有bug。這我同意,而且這是理所當然的事。單元測試本來就不是用來"找Bug"或"證明沒有bug"。它更不是「事後」才補上去的。甚至我可能還會說,"測試"還不是它的主要目的。這些都是一般人對單元測試的誤解。

單元測試是設計的工具。它讓你以完全不同的角度去看待你的程式架構。當你的設計不易測試或你的測試程式碼不易讀時,它就是在提出警告:也許你需要做重構,也許架構不適合需要重新思考過。它強迫你多花一點時間去看待你的設計。我想任誰都可以看得出來我對設計的重視,這部分我歸功於單元測試。很多人會談到用了單元測試後bug會大幅減少,是因為更乾淨的架構讓bug一開始就不易孳生。

多花了時間去思考設計,省下的是許多未來維護的成本。加上它可以被看成是executable documentation,後人要了解修改架構,也會容易許多。在臺灣,程式"完成"後架構一團亂,用了一堆的"hack",要整合或修改得花很多時間居然被視為理所當然的事。

如果對維護不注重,老實說程式怎麼寫都可以完成,讀我的回覆也完全是浪費時間。愛睏魚說有這麼多人用Singleton都沒事,就好像說以前的人只用goto還不是能完成一樣。這麼說也沒錯,不過它是標準不注重維護的人會說的話。

「正方也永遠可以辯駁反方的論點」是事實嗎?目前為止,已證明了denny所做的完全沒有改善我提出的缺點。對於Singleton正方也只有「可以利用compiler來強制生產一個實體」這個論點成立,只有這個我的替代方案得"繞路"才能做到(不是做不到)。除了這外正方可否提出其它新的論點?

但請不要再說「濫用x是不適當的」或類似的話。都已經說是「濫用」了,當然「不適當」。不管x放什麼都成立,這句話是一個tautology,不是我的論點。
作者 : lcwdl(混世魔王) 貼文超過500則人氣指數超過10000點
[ 貼文 951 | 人氣 10894 | 評價 1100 | 評價/貼文 1.16 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 上午 05:11:53
=== 以下給COCO,如有高血壓請直接跳過 ^^ ===
對愛睏魚貼的cliche很興奮,遇到我的反對意見就說我只想贏。是否很不公平?我一直都就事論事。如果嫌字太多而不去看我的回應,你的文章怎能把同樣的字浪費在某些沒有意義的文字上,說別人只想贏,是"信仰"般的見解,而不提出新論點,浪費讀者的時間?省下了那些字,可以說你「無缺點的Singlegton應用例」。而不必說「如果」有一個完美的例子...
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 上午 06:02:17
Coco 大大, 關於 Singleton 的討論似乎是離開了樓主
的題目太多了 (這也是我之前不參與其中的原因). 不過, 樓主的題目
的前題 "Singleton實在是很實用的pattern。" 本身就是錯的.
一個前題錯誤的題目根本就沒討論的意義. 好吧, 我們就一起騎劫
樓主的題目 去討論 Singleton 吧.

比起 Coco大大 圓滑的論調, 混世魔王大大 是有點火, 酸溜溜
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 上午 06:34:54
(對不起, 按錯了. 續上文 )

比起 Coco大大 圓滑的論調, 混世魔王大大 是有點火, 酸溜溜的論調,
看起來彷彿連關於 Singleton 的論點也有點偏頗. 不過, 看過了
混世魔王大大 [2010/11/26 上午 05:09:39] 這一篇回覆之後,
我也覺得 混世魔王大大 是有的道理的.

話說, 我幾年前在我的程式裡, 加入了一個 用 Singleton 的 class.
那時候, 我真的覺得這個 class的設計 是十分好的. 因此, 我不僅
自用, 還把它發佈給同事們一起使用. 但, 這件事讓我後悔到今天呢,
每次帶新同事, 要再解釋一遍. 開發每個程式時, 也要考慮會不會
影響到它. 這個 用 Singleton 的 class, 就彷彿是一隻連續數年
繞著我的頭在飛的蒼蠅般, 髒髒的 但又 殺不死 趕不走.

如果讓我從頭再選, 我是絕對絕對不會用 Singleton pattern 的.
這麼多年的 programming 生涯, 使用 Singleton pattern
的就只有那一次, 但, 就這麼一次, 已足已令我連續後悔數年
至今. 如果大量使用它, 後果實在是不堪設想了.

Coco 大大, 如果把維護的成本也算上去, 真的還值得去使用
Singleton pattern 嗎?



作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 上午 11:30:36
大家實在是離題太遠了,這篇的重點本來就不是singleton好不好用、該不該用、或是singleton本身有什麼優缺點,而是新作法與舊做法的比較。如果你本來就否定singleton,而且也不認為有什麼新做法能夠改變這件事,那很抱歉,這串討論對你可能沒有任何意義。

從頭說起,原由是因為我覺得各種舊做法都有不便之處,才有新法誕生。但新法當然也有缺點,例如之前提過的,數量限制的強制力減弱了,還有之前沒提到的,這個版本因為有循環include的問題沒切割好,在gcc下編不過,後來我改了個新版。因為一個人的角度總有盲點,所以這類針對新法缺點的探討,才是這篇存在的目的。

這裡提供幾個點可以注意。
1.從用法和概念來說,singleton container和Loki的singleton holder非常類似,主要差別是Loki版的singleton class和target class之間沒有繼承關係,而是friend關係。

2.雖然policy base class design強調的是多重繼承,不過在singleton container中的policy並沒有使用繼承(Loki版我沒特別注意),至於BaseSingleton其實只是個interface,所以跟JAVA支援的繼承模式應該是一樣(據我所知,JAVA支援單一繼承,但是可以多重繼承interface,應該沒錯吧?),還有,一開始的版本是沒有BaseSingleton的,它是為了SingletonManager才存在。

3.本來singleton container是以phoenix singleton為主軸實作,但後來發現在 _cexit() 之後便無法復活了,原因是createFlow中的static mutex沒了。我還沒看過Loki版有沒有這個問題,或是它怎麼解決,或者有人有簡單的解法?

4.<<Modern C++ Design>>中有提到,即使用了double lock check仍然有風險,這個問題沒有明確的解決方案。加了volatile就一定安全嗎?還是非得用平台相依的指令才行?
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 01:30:14
>Coco 大大, 關於 Singleton 的討論似乎是離開了樓主
是,這個議題大部份的討論,不是原樓主要討論的主題。
不過,引發的討論雖離題若有益"健康",也請樓主海涵了 ^^

為求尊重,先回一下,樓主的話好了
>>Singleton<target class>目的在防止產止多個targt class的實例。
>>但target class成了後門,可以產生多個實例。
>的確,target class並不是singleton,因為當初就是希望可以不用修改target class
>直接套上singleton的功能才會這樣寫,而Sintleton<TargetClass>是不同的class,
>應該可以算吧(算不算不重要),總之,這套做法把要不要用singleton的選擇權留給了user,
>也許最後的結果變成全域存取和其他的性質重了點,限制物件數量反而沒那麼強制,
>這是singleton container的特性沒錯
我覺得像是你違反了singleton的本意了。
如果target class不是singleton,那麼用singleton包起它來,做什麼?
singleton的private建構式,就是不給user選擇權。
如果user不會出錯的做選擇(例如知道target不能拿來製造物件),那又何需Sintleton去包它。
從你原始貼文看來,目的是因為經常改寫 target class 為Sintleton的花費太高?
所以才寫一個繼承target(但不改變 target) 的 Sintleton container 來達成單一化target?
target只要不改寫,就不可能單一化target,花費太高的問題其實是可以妥協一下,例如
只需把target的建構式改成private,然後再加一行 friend 給Sintleton container,這樣就成了。
這樣修改的花費應不會太高吧?
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 02:20:27
>混世魔王:因單元測試是我反對Singleton的主因之一,有大半篇幅單元測試被受到攻擊。
>Gary:如果把維護的成本也算上去, 真的還值得去使用 singleton pattern 嗎?
>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
若沒有好的理由而使用了sigleton而導致你們說的缺點,我同意就不要使用。
我的重點還是在於"我不能武斷的說天下沒有使用singleton的場合和理由"。
還有一個"次要"重點:你們說的singleton的缺點好像都沒有錯,但不一定是singleton的"必然"缺點。
例如說(要舉例,還真的有點傷腦細胞^^)
有一個參數索引類別(以下稱CParmIndex),除了建構時的運算外,基本上它是唯讀的。
CParmIndex只能有一個,應用程式的其它地方,都只能指向它索引,不能自己產生CParmIndex。
(因為可能重新建構)
那麼它應該算是singleton的應用場合。那值不值得?
CParmIndex因是唯讀的,所以沒有混世魔王說的單元測試問題(是吧!?)
CParmIndex的singleton設想,正是避免意外的產生雙頭馬車而導致資料不一致時的額外維護負擔。
所以應也不存在提高維護成本。
或許你要提出質疑:那就使用global就好了!
singleton真的和global很不一樣:
global 物件不能保證該類別的物件唯一性(光是這點 global就玩完了)
global物件無法重構。但singleton的物件可能重構,也就是singleton的物件可以是抽象的。
例如,CParmIndex可能因為某項因素的改變而需重構。
這時可能連getInstance()都被保護起來,避免程式儲存 getInstance()返回的指標,而使用到
已消失(舊)的CParmIndex。取而代之的是一個索引介面。
像這樣的一個例子,是不是該使用singleton?

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 02:39:10
我剛看了一下樓主 po 的程式碼,要說是 Singleton Container 是不太恰當,因這個 Container 所能裝的並不是 Singleton,應視為獨一物件的 Smart Ponter 比較恰當,意思是經由這個 Container 取得的物件絕對是同一個,為什麼要說那是 Smart Ponter,因當無使用時似乎也能自動 delete。

樓主若是要逹到這樣的目的,是蠻有獨到見解的,另外再取個適當的名稱免得被誤解
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 04:12:35
>我覺得像是你違反了singleton的本意了。
>如果target class不是singleton,那麼用singleton包起它來,做什麼?
有幾種情形
1.target class來自library或別人的code,且不是singleton,但是你需要一個target class singleton,但是你根本沒有source或是你不想改它
2.target class在某個專案不是singleton,但是在另一個專案中必須是singleton(或是相反),而除此之外相同,這時就可以使用singleton container而不用維護兩個版本
3.我實際遇過的情況是,在改寫global operator new和delete時,內部需要mutex物件,這時不能用local因為new和delete中的mutex必須是同一個,但是也不能是global因為你無法保證它比其他global物件先建構完成,這時直接在new中使用mutex的singleton就是唯一的辦法,而且這個singleton還必須特製,內部不能再使用new產生物件(這就是我之前提過需要避開new的特殊情況)。但是mutex本來就不該是singleton,所以你不會去改它,只好包上singleton的外衣。這個動作當然可以手動自己做一次,但是一行
Singleton<Mutex,NoUseNewPolicy>::getSingleton().Lock();
就解決了所有問題
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 04:23:06

>我剛看了一下樓主 po 的程式碼,要說是 Singleton Container 是不太恰當,因這個 Container 所能裝的並不是 Singleton,應視為獨一物件的 Smart Ponter 比較恰當,意思是經由這個 Container 取得的物件絕對是同一個,為什麼要說那是 Smart Ponter,因當無使用時似乎也能自動 delete。
哈哈哈,命名問題的確有困擾過我
最後決定用這個名字的原因是,因為它的用法(或者應該說語法)其實跟vector<>很像,只是是兩個極端
當你有TargetClass,想要一串TargetClass時可以寫vector<TargetClass>
當你有TargetClass,想要唯一TargetClass時可以寫Singleton<TargetClass>
所以用singleton container這個名稱
感謝你的建議

delete不是自動喔,是自己呼叫Singleton<TargetClass>::releaseSingleton();
如果要自動要搭配SingletonManager才行,而且SingletonManager本身還是必須手動呼叫releaseSingleton()
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 05:30:10
>1.target class來自library或別人的code,且不是singleton,
>但是你需要一個target class singleton,但是你根本沒有source或是你不想改它
這點 cxxlman 說的是,這樣的東西是不應該叫singleton了。
若還是強行做singleton,只能把兩者包起來變成lib,只開放singleton部份的介面。
不然,還是取別的名稱吧^^

>2.target class在某個專案不是singleton,但是在另一個專案中必須是singleton(或是相反),
>而除此之外相同,這時就可以使用singleton container而不用維護兩個版本
這樣旳情況,通常的做法是在project predefine 一個switch名稱。target class由這個名稱
決定建構式是public還是private。
不過一個類別在不同專案,可能是也可能不是singleton,我會比較傾向魔王說的,兩者都不要用singleton。
我能想像的singleton合理應用,類別本身就已顯現唯一的性質。但純屬個人看法。
程式應用本就千變萬化,沒有絕對的道理。

>3.我實際遇過的情況是,在改寫global operator new和delete時,內部需要mutex物件...
看的有點花  @∼
就當作你有一些很特別的應用場合吧 ^^
無論如何,前面兩點還是可供參考。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 05:38:10
>> 混世魔王:因單元測試是我反對Singleton的主因之一,有大半篇幅單元測試被受到攻擊。
>> Gary:如果把維護的成本也算上去, 真的還值得去使用 singleton pattern 嗎?
>> :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
> ...
> 有一個參數索引類別(以下稱CParmIndex),除了建構時的運算外,基本上它是唯讀的。
>...

如果遇到這樣的情況, 我大概會寫一個 class, 包裝起所有的
起始索引工序 和 索引介面, 而建構式之內只把 data member
被始成零, 需要時才掛上資源. 然後, 加入一 global 物件給用家
使用.

唯一性嘛, 只要透過控制哪些 class 能呼叫 起始索引工序,
應該就能某程度地達成. 如果用家明知自己開出來的 class
是沒功能的空物件, 還是想要開一個的話, 就隨他吧.

但是, 我大概只會建議用家繼續使用 global 物件,
而不會強制唯一性的, 就是說... 為什麼一個程式
只能有一個索引呢? 說不定我或其他用家 將來會想擴充
它呀.


作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 07:35:57
>如果遇到這樣的情況, 我大概會寫一個 class, 包裝起所有的
>起始索引工序 和 索引介面, 而建構式之內只把 data member
>被始成零, 需要時才掛上資源. 然後, 加入一 global 物件給用家
>使用.
和歷史上對goto的爭論一樣。一個使用goto合適的例子,總有另一個
不使用goto的取代方法。所有使用while的程式也都可以使用for來取代,
但這不能說 while 不該使用吧?贊成可使用goto的人,並不堅持goto有
不可取代性。
我舉這個例子在表明它singleton的適用性,不在於不可取代性。

>唯一性嘛, 只要透過控制哪些 class 能呼叫 起始索引工序,
>應該就能某程度地達成. 如果用家明知自己開出來的 class
>是沒功能的空物件, 還是想要開一個的話, 就隨他吧.
唯一性如果是應用上合理的要求,那麼達成唯一性的方式,並不一定是
使用標準的做法。我前面提到的"廣義"的singleton,都是singleton。
但殊途同歸,最後都會有前面說的後遺症。
(但後遺症並不是所有的singleton必然會有,如我所舉的例子)

>但是, 我大概只會建議用家繼續使用 global 物件,
前面提了啊!不能重構。

>而不會強制唯一性的, 就是說... 為什麼一個程式
>只能有一個索引呢? 說不定我或其他用家 將來會想擴充
>它呀.
不是無的放矢。
我舉的例子是實際應用簡化的。
參數表是跟根據不同的裝置選項,建構出不同的參數。
程式所有的地方都要根據這個參數索引來運作。
(例如裝置的頻率,setup time, hold time, propagation delay, puls width...)
如果發生了使用的參數不一致的情況,會會有不可預期的錯誤發生。
而且相檔難debug。所以才要有唯一性,而且在裝置選擇改變重構時,
要保證沒有"人"正在使用這個參數索引。
可不可以擴充?可以啊!但不能舊的索引表和擴充的新索引表兩個物件同時存在。
既然改了新的,舊的就不能生成物件(應該程式碼不見了吧),才能維持唯一性。

需要唯一性物件的實際例子,我能想得到的可能不多,但也還可以舉。
像寫一個較大的應用程式,會需要一個專門處理exception的物件。
因為exception機制可以是巢狀的,而exception的發生也有等級(如warning, fail, fatal error...)
所以處理上要根據等級和目前接到exception的所位置決定是不是要再往上層丟(fatal error要一直往
上丟,直到最上層)。這樣的exception規劃合理吧(我有實作喔)?
那麼,這個處理exception的物件當然你會想要它是唯一的exception物件,否則就亂了套。
不管物件是如何產生的,建立了第一個就不希望有第二個來攪局(否則就亂了套)。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/26 下午 10:15:45
> 和歷史上對goto的爭論一樣。一個使用goto合適的例子,總有另一個
> 不使用goto的取代方法。所有使用while的程式也都可以使用for來取代,
> 但這不能說 while 不該使用吧?贊成可使用goto的人,並不堅持goto有
> 不可取代性。
> 我舉這個例子在表明它singleton的適用性,不在於不可取代性。

請讓我先說明一點, 我是 混世魔王大大 口中的那一種不負責任的編程人員,
對於我來說, 編程式, 就是解決問題, 大原則就是 以低成本完成.
只要是成本更低, 別說是 singleton, 就連 static local variable 呀,
MACRO statement 呀, 啥我也會用.

Coco大大, 我覺你以 "goto爭論" 作為論點的一部份, 是在狡猾地
賣弄文字遊戲, 基本上就是在說: 因為有情況 goto 適用, 所以
goto 就可被廣泛應用; for loop 不是完美的, 所以它跟也
不是完美的goto 無分別. 說這是狡猾, 因為你 over-generalize
實際的情況而得出這類結論. 避開了雖同為工具, 但質量各有不同的現實.
就算真的有 goto 更好的例子, 也是極少數的情況吧, 相比起
for loop 和 while loop, goto 的重要性是很低的. 最重要的是,
它是可以用 for loop 或 while loop 去取締的. 算算成本呀,
維護成本高 重要性很低 又非必要的 goto, 捨棄它來換取
更統一的原碼去方便管理, 是很值得的. 在現實世界, 處於淘汰邊緣的 goto,
也引證了這一點. 說到成本呀, 人們就會變得理智, 什麼理想,
什麼爭論, 也變會變得黯然.

維護成本高 重要性很低 又非必要的 Singleton, 捨棄它來換取
更好的原碼管理, 若何?

再現實一點, 你現在的 class objects 裡, 有多少是 Singleton ?
如果你的下屬給你寫了一個用了 Singleton pattern 的程式,
你會如何處理? 又或者, 你的下屬下載了樓主的
Singleton container, 用在給你的程式中, 若何?
(請真的設身處地去想...)


>> 但是, 我大概只會建議用家繼續使用 global 物件,
> 前面提了啊!不能重構。

不用重新建構, 只要把 data members 重新初始就可以.
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 上午 01:00:15
>Coco大大, 我覺你以 "goto爭論" 作為論點的一部份, 是在狡猾地
>賣弄文字遊戲, 基本上就是在說: 因為有情況 goto 適用, 所以
>goto 就可被廣泛應用;
No! 如果有人這樣認為這是我的意思,真的很抱歉。
goto 和 singleton 一樣少用為妙,儘量不用。
(很希望這一句可以放大,可惜本程設這邊不能放大字體,免得又被誤解)
我舉的例子只是在說明sigleton有它適用的場合。

>for loop 不是完美的, 所以它跟也
>不是完美的goto 無分別. 說這是狡猾, 因為你 over-generalize
>::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
唉....這也"完全"不是我的意思!
好吧,我會好好的檢討我的國文吧!

>維護成本高 重要性很低 又非必要的 goto, 捨棄它來換取
>更統一的原碼去方便管理, 是很值得的.
實在猶豫要不要又岔到goto去,尤其是顯然我的國文能力出現問題之時 :(
這樣吧!
如果這句話的前面加上"如果"兩個字,我完全同意你的話。
我也百分之一百同意,適合goto的場合,很少很少(我只"曾"用在兩個場合)。
(我沒說要廣泛的用啊,真希望可以放大)
但就算少之又少,
"如果"有場合使用goto可讀性高,維護成本比其它方式低,還是不可以用嗎?

>再現實一點, 你現在的 class objects 裡, 有多少是 Singleton ?
很少很少很少很少......真的很少(不能放大,只好多寫幾遍^^),這不是討論的重點。

>如果你的下屬給你寫了一個用了 Singleton pattern 的程式,
>你會如何處理? 又或者, 你的下屬下載了樓主的
>Singleton container, 用在給你的程式中, 若何?
沒有差別待遇:該用就用,錯了就改。
不論是goto,singleton謱是其它的東西,原則都是一樣的。
singleton寫在錯的地方,其它的工具也是一樣,錯了就改;
singleton寫在對的地方,其它的工具也是一樣,都是好程式。


>>> 但是, 我大概只會建議用家繼續使用 global 物件,
>> 前面提了啊!不能重構。
>不用重新建構, 只要把 data members 重新初始就可以.
我用建構這個字眼,已經暗示索引的改變不是那麼單純。
所以我說singleton的物件可以是抽象的。
(索引的interface一樣,但可能對應到完全不同的索引物件,不是像查表格這樣單純)
作者 : d8231657(denny)
[ 貼文 58 | 人氣 4556 | 評價 70 | 評價/貼文 1.21 | 送出評價 10 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 上午 02:09:21
>若還是強行做singleton,只能把兩者包起來變成lib,只開放singleton部份的介面。
這句是什麼意思?看不太董耶

>這樣旳情況,通常的做法是在project predefine 一個switch名稱。target class由這個名稱
>決定建構式是public還是private。
可行,不過我覺得有點太麻煩

>我能想像的singleton合理應用,類別本身就已顯現唯一的性質。但純屬個人看法。
這是singleton pattern原本嚴格的定義沒錯。
不過如果換個角度想,不要把singleton container當成是singleton pattern的實作,把它想成是一個
"能取得TargetClass的一個特定物件的產生器"如何?

>看的有點花  @∼
那我解釋清楚一點
我在寫一個可以偵測memory leak的記憶體管理library,
因此必須改寫global operator new/delete,
這樣我才能在user使用new時順便紀錄一些必要資訊,並在delete時清除。
user程式可能是multithread程式,因此必須考慮有兩個以上thread同時呼叫new或delete,
所以new/delete內存取那些必要資訊時必須先用mutex物件鎖定。
new/delete都是global function,要使用同一個mutex物件的方法就是共用一個global mutex物件。

Mutex global_mutex; //必須在第一次new呼叫前建構完成
operator new()
{
    global_mutex.lock();
    //紀錄資訊
    global_mutex.unlock();
}

但是如果user用了其他的global物件,且該物件的建構式內有使用new配置記憶體,那該建構式呼叫前global mutex物件必須建構完成,否則進入new後就會使用到尚未建構完成的mutex。

class A
{
public:
    A()
    {
     Something *p=new Something();
    }
}
A a; //也是global物件,建構式會呼叫new

問題是同為global物件,c++並沒有任何機制讓你指定建構順序!
這時用singleton取得mutex可以解決問題,因為singleton具有"第一次使用前建構"這個特性。
但是mutex別處可能也要用,不可能直接將他改成singleton,
只好另外寫一個singleton class將不能改的mutex包裝在內,

class MutexSingleton
{
    static Mutex *mutex;
public:
    static Mutex& getSingleton()
    {
     if(mutex==0) mutex=new Mutex();
     return *mutex;
    }
}
Mutex *MutexSingleton::mutex=0;

operator new()
{
    MutexSingleton::getSingleton().lock();
    //紀錄資訊
    MutexSingleton::getSingleton().unlock();
}

結果產生新的問題,new Something()=>getSingleton()=>new Mutex()=>getSingleton()=>new Mutex()......無窮遞迴!
所以至少必須再把new Mutex()改成用malloc或其他涵式配置記憶體才行。

這就是"把非singleton類別披上singleton外衣"的實例。
但是多寫一個MutexSingleton class我覺得實在很礙眼,每次要實作singleton也很麻煩又容易出錯,重複的code可以提取出來共用不是很好?而且我遇到這個問題之前singleton container就已經完成,所以就直接使用singleton container

operator new()
{
    Singleton<Mutex,NoUseNewPolicy>::getSingleton().lock();
    //紀錄資訊
    Singleton<Mutex,NoUseNewPolicy>::getSingleton().unlock();
}

這樣有看懂了嗎?
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 上午 07:54:06
>> 維護成本高 重要性很低 又非必要的 goto, 捨棄它來換取
>> 更統一的原碼去方便管理, 是很值得的.
> ...
> "如果"有場合使用goto可讀性高,維護成本比
> 其它方式低,還是不可以用嗎?

"捨棄它來換取更統一的原碼去方便管理, 是很值得的.", 這一句
的捨棄, 是真的是在說 縱然 goto 有場合更好, 也捨棄它.
多一個可用的指令, 就多一系列的錯誤. 或是說, 如果不容許
使用 goto, 就不可能因為 goto 犯錯. 不過, 這個問題已經
變成一個取捨的問題, 即是 更統一的原碼 和
更靈活 權衡問題. 當然, 我是覺得前者比較重要的.
(請千萬不要概括我的意思成... "更統一的話 while loop 也豈不是要捨棄".
權衡輕重... 權衡輕重... 經驗是不可缺的)
Singleton 的考慮類同...
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 上午 11:26:37
>>若還是強行做singleton,只能把兩者包起來變成lib,只開放singleton部份的介面。
>這句是什麼意思?看不太董耶
就是把你的 target container 寫成library給project使用。
因為看不到 target class 的原碼,也就不會有再建立第二個target 物件的問題。
getInstance 則是返回 target 的 interface 指標。
既說是"強行"就是勉強而為,只是一個可能性。所以不重要囉。

>不過如果換個角度想,不要把singleton container當成是singleton pattern的實作,
>把它想成是一個"能取得TargetClass的一個特定物件的產生器"如何?
行啊!只是改個名子比較好。例如unique, individual ^^
雖然從singleton的字面解釋,也沒什麼不對。但singleton在程式中,有它專有的意義。

>>看的有點花  @∼
>那我解釋清楚一點
>我在寫一個可以偵測memory leak的記憶體管理library,
>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>這樣有看懂了嗎?
OK,本來我就不反對有適用singleton的場合,所以我看不看得懂也就不重要了 ^^

作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 上午 11:45:57
>"捨棄它來換取更統一的原碼去方便管理, 是很值得的.", 這一句
>的捨棄, 是真的是在說 縱然 goto 有場合更好, 也捨棄它.
>多一個可用的指令, 就多一系列的錯誤. 或是說, 如果不容許
>使用 goto, 就不可能因為 goto 犯錯. 不過, 這個問題已經
>變成一個取捨的問題, 即是 更統一的原碼 和
>更靈活 權衡問題. 當然, 我是覺得前者比較重要的.
>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
並不反對(應該說舉雙手贊成)個人或團體,對程式的寫法或命名有一些制約,
包括對goto 的禁用(畢竟不用也不會死人)。
但我們談的是,goto該不該"全面"禁用或淘汰。
就我來說,是採比較彈性的作法,例如對goto的制約。
我會說:只能在兩場合使用 goto,但若是參與project的工程師能提出
第三種使用goto適合的場合,不排除可以經由討論認可放行。
(目前為止我認為只兩種場合適用goto,但不排除有第三種,畢竟我不是神)
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 01:27:03
>但我們談的是,goto該不該'全面'禁用或淘汰。

對不起, 也許是我過於現實, 滿腦子也只有實務和管理,
忽略了理論層面的東西... 該不該 淘汰goto 嘛,
如果沒有歷史因素的考慮, 我會說應該從編譯語言
中把 goto 移除. 不過, C/C++ 由來已久, 關係
千絲萬縷的, 出於歷史因素考慮, goto 是應該被留下的.
(註: Singleton pattern 沒有這歷史因素的, 可直接淘汰.)

不過, 如果是 新的程式語言, 好像是 JAVA, 就淘汰goto吧,
噢, 實在 JAVA 已經淘汰了 goto. 請參考:
  "White Paper The Java Language Environment"
  [2.2.6 No More goto Statements]
  http://java.sun.com/docs/white/langenv/Simple.doc2.html
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 02:47:30

弄一個例子給大家玩玩

int i = 1;
i = i+i;
while(i < 10000)
{
  i = i+i; // 不用 goto 這裡要重複一次
  ......
}


int i = 1;
START:
i = i+i;
if(i >= 10000) goto END;
  ......
goto START;
EBN:
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 02:50:34
最後那行打錯= = 改一下


int i = 1;
i = i+i;
while(i < 10000)
{
  i = i+i; // 不用 goto 這堶n重複一次
  ......
}


int i = 1;
START:
i = i+i;
if(i >= 10000) goto END;
  ......
goto START;
END:
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 04:08:35
CxxlMan,
Coco 大大 和 我所說的 goto 比較好的情況,
絕對不是你所列舉的這一個, 而且, 你所舉的
例子, goto 是較差的.

goto 較好的情況嘛, Coco 大大說有兩個, 但我只認識一個,
就是做 error handling 的時候, 當 error 發生,
goto 直接跳到 error 處理工序. 請參考
  http://www.cprogramming.com/tutorial/goto.html
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 05:33:02
我的意思是不用 goto 這個 i = i+i; 得做兩次
有沒有辦法只做一次就好
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/27 下午 10:03:55
>goto 較好的情況嘛, Coco 大大說有兩個, 但我只認識一個,
>就是做 error handling 的時候, 當 error 發生,
另外一種是用在結東深層巢狀迴圈(break 只能脫離一層迴圈)。

>不過, 如果是 新的程式語言, 好像是 JAVA, 就淘汰goto吧,
>噢, 實在 JAVA 已經淘汰了 goto. 請參考:
不能這麼簡單的說:JAVA 已經淘汰了 goto
JAVA 的 goto 隱身在 continuebreak 中(continuebreak在java強化成含有goto的功能)。
java "真正"去掉C裡面有爭議的東西應是指標。
指標的箏議性和危險性,絕對遠大於goto,singleton。
本來C++增加了reference的功能後,是有機會去掉了指標的。
(沒去掉的初始原因應是相容問題)
reference的加入,應該會大大增加反對指標一方的強度。
但STL的出世,把指標推向了另一個層之,現在反而少人再談指標是不是該淘汰了。
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/29 上午 07:21:31
個人覺得這篇愈來愈離題了, 或許另開一個較好.

以Singleton而言, 個人會比較認同混世魔王的言論. 維護性, 你會在將來愈來愈知道它的重要性. 只是, 很多東西, 在最初的架構時就要搞好 (分析設計階段), 而不是到programming時, 才來講求它的維護性, 那麼就太慢了. 愈是會coding的人, 愈會沈入到coding&testing的開發循環, 這樣反而對公司非常不好. 以前曾高薪找了一個號稱為某公司的台柱, 我承認交辦的事完成的很快, 執行的各方面都沒問題, 但唯一無法接受的是, 所有的過程沒文件, 程式也沒註解, 所以他再怎麼會寫, 我也不想用他. 因為, 他愈寫愈多, 將來維護的成本也就愈多. 無法體會的話, 請再業界多待幾年就知道了.
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2010/11/29 下午 12:44:14
>以Singleton而言, 個人會比較認同混世魔王的言論. 維護性,
>你會在將來愈來愈知道它的重要性. 只是, 很多東西, 在最初的架構時就要搞好
>(分析設計階段), 而不是到programming時, 才來講求它的維護性, 那麼就太慢了.
很可惜,我已經沒有太多的將來了^^
"很多東西, 在最初的架構時就要搞好... 而不是到programming時, 才來講求它的維護性"
這個應該是大家都同意的,所以沒有爭議。
有爭議的是singleton是不是該"全面"禁用。
我也舉了一個CParmIndex的例子(好像舉了兩個),適合singleton應用的場合。
CParmIndex也沒有架構和維護的問題,我認為類似的情況singleton可以用。
當然你也可以反駁我,但希望就已討論的材料,例如我舉的例子。
"很多東西, 在最初的架構時就要搞好... 而不是到programming時, 才來講求它的維護性"
好像又回到原點:這個本來就沒人反對...
 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.375