This article is about a multi-threading technique. For the lockstep protocol variant, see Active
objects.
The active object design pattern decouples method execution from method invocation
for objects that each reside in their own thread of control.[1] The
goal is to introduce concurrency, by using asynchronous
method invocation and a scheduler for handling requests.[2]
The pattern consists of six elements:[3]
- A proxy, which provides an interface towards clients with publicly accessible
methods.
- An interface which defines the method request on an active object.
- A list of pending requests from clients.
- A scheduler, which decides which request to execute
next.
- The implementation of the active object method.
- A callback or variable for
the client to receive the result.
Command模式的關鍵在於只包含一個 Execute方法,子類在實現這個介面時,在Execute方法中,完成特定的任務。可以說,這是一個非常簡單的模式。《ASD》中提到了該模式的三種用法:1. Invoker可以和任意一個Command掛鈎,而且不需要瞭解這到底是個什麼ConcreteCommand,然後在需要的時候調用這個 Command對象的Execute方法就行了。這在訊息驅動的的系統中非常常見,每個trigger就是一個invoker。那麼如何把Command 和invoker掛鈎呢?方法很多,最cool的方法是在系統外用一個設定檔來指定。這樣不需要重新編譯就可以改變軟體啟動並執行方式。可以參考 Source Insight的介面。Source Insight中可以任意配置功能表項目和工具列按鈕。其實現應該就是應用了這種Command模式。2. 上面的方法是否讓人想起了Template模式?有點相像吧。順著這個思路去想,就可以把Command模式應用於Transaction。讓一個類來解決Transaction的init和uninit問題,中間包含一個Command的隊列。這樣就可以把這個隊列中的全部command當作一個 transaction了。這樣的作法可以把Transaction的實現和邏輯分離開來,是很漂亮的實現。同樣的思路,也可以用在類似的問題上,需要 init和uninit,中間有不定量的操作。3.如果真的用來解決transaction問題,那麼就必須具備roll back的能力。然而這個很容易實現,只要在command類中,添加undo方法就可以了。剩下的活交給invoker來處理。4.此外還有一個附帶的好處。command類和一個單獨的execute方法其實很相似,但是command類的對象有生命週期,可以由程式來控制。因此,一個command對象,可以在提交了很長時間以後再批量執行。 除了這些以外,《Design Pattern》還提到了Command模式的其他使用方法。雖然這些方法未必實用,但我還是把它們列在這裡:
1.command對象和command對象的序列都可以serialization。這樣如果軟體被有意或無意的中止(例如crash),在重新啟動後,還可以接續之前沒有完成的任務。2.Command模式如果和Composite模式接合,就可以作出MacroCommand。^_^,這個idea雖然很cool,但是可以用到的地方大概不多吧。 Active Object模式不屬於《Design Pattern》23模式。實際上,她是一種特殊的Command Queue。其特殊之處在於:1. 隊列的擁有者會順序地執行隊列中所有Command對象的Execute方法。(這個其實不算特殊)2.Command對象在自己的Execute方法結束前,可以把一個新的command對象(實際上常常是這個command對象自己)再加到隊列的尾部。看出來了嗎,這個隊列有可能不會終止的,他可以一直執行下去。這個可以作為一個應用或者服務的主模組了,想像一下她可以作多少事情吧。《ASP》指出這個模式可以用來在一個線程中處理多任務的問題!!! ^_^ 太cool了。如何處理呢?你可以把每個command對象看作是一個任務。他在Execute函數中,處理自己的任務,在任務告一段落時,記錄自己的狀態,然後把自己插入到隊列的尾部,結束Execute方法。當隊列輪完一周后,又會再次執行這個command對象的Execute方法。 ^_^ 很cool吧。那麼這種方法和多線程的方法相比有什麼有缺點呢?最大的優點是,所有的command都在同一個線程中,因此切換時,不需要進入核心模式!!超高效啊!!而且,可以有很多很多的command,數量上遠遠超過多線程的數量。缺點嘛,是這種方法需要使用者自己來實現調度,另外這其實是一種非剝奪模式的多任務,如果command處理不好,就會連累其它所有的command,因此實際上比多線程要更複雜。(嘿嘿,程式員能夠怕麻煩嗎?)還有一點,Active Object運行於單線程,也就是說,她不能享受多處理器或多處理器核心帶來的效能上的改善。其實,這最後一點是非常致命的一點。也就是說,在當前intel的超執行緒CPU機器上,如果系統的負擔並不重的時候。Active Object的效率有可能比多線程更低。Anyway,這是一個非常有趣的模式。只是一般的程式員可能沒有機會用到。但是請記住她,也許能有那麼一次機會,可一用她來爽上一把。