Introduction
Asynchronous Completion Token是一個design pattern。在asynchronous event-driven application中,我們可能會有一種情況是當asynchronous operation完成後,回傳給initiator時,會不知道是由哪個asynchronous operation所產生的,這時候我們透過Asynchronous Completion Token來解決這個問題。
Context
適用於event-driven的應用程式。在其中使用者非同步地去呼叫operation,接著處理相對應的asynchronous operation的完成事件。
Problem
當client端應用程式透過非同步的方式呼叫一個或多個服務,服務會透過completion event來回應結果給clinet端應用程式。這時候應用程式必須要能夠解多工(demultiplex)這個事件到對應的handler做處理。在此同時,可能會有以下幾個考量因素:
1. service本身不知道client的環境,所以有關completion event demultiplexing的權責要交由 client去處理。
2. 在service跟client之間,我們希望用越少的communication overhead去決定如何解多工 並處理completion event。
3. 我們同時也希望能夠花越少的時間去解多工completion event至對應處理該event的handler
Solution
要解決以上的需求,我們的做法是當我們執行一個asynchronous operation時,同時丟進一個如何處理completion event的資訊。當opeartion完成時,application可以透過個資訊來知道如何處理這個completion event。
更詳細的講,這個特殊的information就是此pattern的重點Asynchornous Completion Token,在其中可能存放了completion handler的function pointer或是object
Structure

Participant and Responsibilities
Initiator
-以非同步的方式呼叫service
-決定completion handler
Service
-提供非同步的服務
Completion Handler
-定義處理非同步運算結果的interface
ACT
-存放處理非同步運算結果的completion handler,以供Initiator處理completion event之用。
Dynamics

1. 在呼叫asynchronous operation之前,Initiator先產生ACT,並指定要處理結果的
completion handler
2. 當Initiator呼叫asynchronous operation時,把參數連同ACT一起傳過去做處理。
3. Initiator在呼叫之後,可以做其他的動作,甚至可以再呼叫其他的asynchronous operation。
4. 當asynchronous operation處理完之後,service回傳結果連同ACT給Initiator。Initiator透過ACT的資訊得知如何解多工此completion event至對應的completion handler做處理。
Conclusion
此pattern感覺有點像是一個信物。在非同步的系統之下,通常很難掌握原呼叫時期的狀態,這時候ACT就扮演了這個類似信物的角色,當Initiator收到此信物後之後則知道如何處理這個completion event。
此token的概念有點像是GoF的Memento,而Memento也有另一個別名也叫做token,但是使用的時機不一樣,Memento是用在紀錄物件的snapshot,供回之後回存之用。而ACT是存放event handler或是一些initiator的狀態資訊,以供處理completion event之用。
Introduction
Proactor是一個architectural pattern。此pattern主要針對framework或是OS所提供的asynchronous operations,在這些asynchronous operation結束之後會觸發某個事件(此pattern稱此種事件為completion of asynchronous operations)。在架構在這種framework之上的event-driven的應用程式可以有效率的透過解多工(demultiplex)及分派(dispatch)這些事件到對應的service做處理。
Context
適用於event-driven的應用程式,此應用程式以非同步的方式接收及處理各種service request。
Problem
通常event-driven的應用程式可以透過asynchronous operations來提高整個系統的效能。當這些asynchronous operations完成時,會丟出完成的事件來給外部的應用程式來做處理。因此應用程式要能夠解多工(demultiplex)及分派(dispatch)這些完成的事件給原本呼叫此asynchronous operations的client或是某個應用程式服務做處理。在處理這些解多工跟分派的動作時,我們必須考慮到以下幾點:
1. 為了能夠增加延展性跟減少延遲,應用程式不應該因為處理過長的operation來導致無法同時處理很多的完成事件。
2. 為了能夠有較好的throughput,任何不必要的context switching, Synchronization, data movement都應該要避免。
3. 若未來要整合新的service或是改善暨有的service,所需要花的功夫應該越少越好。
4. 撰寫Service的程式碼中,應該完全不會理會到底層複雜的multi-threading或是synchronization部分的機制。
Solution
我們把應用程式服務分成兩個部分
1. 用非同步的方式處理需要花很長時間處理的operation。
2. 透過completion handler來處理這些非同步的operation的完成事件。
把所有的服務都提供一個asynchronous的operation,並且透過handler來"後置"處理這些asynchronous operation的結果。而asynchronous operation是由initiator來觸發,並且由asynchronous operation processor來處理,當async. operator處理完成後,async. operatrion processor會把completion event塞到completion event queue中。
之後Proactor透過Asynchronous Event Demultiplexer從queue中取出completion event,並且把它解多工並且分派到對應的completion handler做處理。
Structure

Participants and Responsibilities
Handle
-代表的是一個OS提供的resource
Asynchronous Operation
-可以非同步處理的operation
Completion Handler
-定義了一組處理asynchronous operation的介面
Concrete Completion Opeation
-根據應用程式需求的Completion Handler的實作
Asynchronous Operation Processor
-負責執行asynchronous opeartions
-負責把asynchronous operations完成的結果置入到completion queue中。
Completion Event Queue
-負責儲存及存取completion event。
Asynchronous Event Demultiplexer
-提供一個blocking method,向Completion Event Queue等待一個completion event的發生。
Proactor
-跟Asynchronous Event Demultiplexer取得completion event。
-分派event到對應的completion handler。
Initiator
-asynchronous operation的觸發者
-有時候也可以扮演concrete completion handler的角色
Dynamics

1. 首先initiator可能呼叫某個asynchronous operation
2. Asynchronous Operation Processor代理initiator去處理這個asynchronous operation, 此時asynchronous opeartion跟async. operation可以同時進行,兩兩是獨立的。甚至initiator可以呼叫其他的async. operation。
3. 當async. operation完成後,會產生一個completion event。async. operation processor會把這個event塞進此handle所對應的event queue。
4. 當應用程式準備好要處理completion events時,則呼叫proactor的handleEvents()。 此method透過async. event demultiplexer向event queue取得completion event,並且分派到對應的completion handler去做處理。
5. completion handler處理async. event的結果。
Consequences
其實這個pattern在java中不是那麼好實作,書中提到的一些例子都是OS所提供的一些library所提供,如POSIX的aio_*(),或是WIN32的overlapped I/O,completion ports。這些在java中沒有類似的對應,但是也許可以透過nio來模擬。
還有proactor pattern跟reactor pattern很多地方都很相似,都是event handling的pattern,但是event產生的方式跟處理的時機不太一樣。書中有以電話的例子來作比喻。
以Reactor pattern來說,Reactor就像是電話公司,我們的電話號碼就是一個handle,而我們就像是"event handler"向電話公司註冊此號碼"handle"。當電話來時,我們的handle的方式就是拿起電話並開始講話。
Proactor pattern的話就像是語音留言。當我要找我的朋友時,發現他不在,我就留一個語音留言說我再找他。相對於proactor pattern,我就像是一個initiator,執行一個async. operation(語音留言),並且透過async. operation processor(語音留言系統)。留言之後,我可以做做我自己的事情,逛逛jsptw。之後,我朋友看到我的留言,就回電話給我,此時他所扮演的角色就是completion handler。
Introduction
Reactor是一個Architectural pattern。目的是讓一個event-driven的應用程式,能夠把產生的事件解多工(demultiplex)並且分派(dispatch)到對應的service做處理。
As Known as
Dispatcher, Notifier
Context
此pattern是應用在event-driven的應用程式。在其中,應用程式可能同時間接收到不同client的service requests,但是卻要同步地(synchronously)且循序地(serially)處理他們。
(註: 這裡的synchorously及serially是相對於asynchronously,也就是同步的呼叫。在同步的呼叫中,caller一定要等callee完成處理後,才能繼續下一個動作,因此才又會是serially。反觀asynchronously process,caller不必要等待callee完成處理就可以做下一個動作)
Problem
Event-driven的應用程式(尤其是server程式)必須要能夠同時處理很多client所產生的service request。而所有的event可以用indication event(如CONNECT及READ)來做區別。但是在處理這些event之前,event-driven的應用程式必須要先把這些indication
event做解多工(demultiplex)跟分派(dispatch)到對應的service。要解決這個問題,我們必須要有以下四個必須考量到的問題
1. 應用程式不應該block在某一個indication event而導致無法處理其他的event,這會導致效能大大的下降。
2. 為了能夠有較好的throughput,任何不必要的context switching, synchronization, data movement都應該要避免。
3. 若未來要整合新的service或是改善暨有的service,所需要花的功夫應該越少越好。
4. 撰寫Service的程式碼中,應該完全不會理會到底層複雜的multi-threading或是synchronization部分的機制。
Solution
用Synchronous的方式去等待來自不同的event source(如connected socket handles)的indication event,並且整合了demultiplex跟dispatch的機制在其中。除此之外,我們把有關demultiplex跟dispatch的機制以及application-specific處理event的邏輯分離。
更詳細的說,我們把處理某個indication event的邏輯看成是一個service,而此service必須實作成一個"event handler",並且註冊在一個稱為"reactor"的元件當中。"reactor"透過"synchronous event demultiplexer"來等待某個indication event的發生。當indication event產生時,則回傳給reactor,並且找到對應的"event handler"用同步的方式dispatch給它做對應的處理。
Static

Participants and Responsibilities
Handle and Handle Set
-Handle代表的是一個event source。
-Handle Set代表的是一組handles。
Synchronous Event Demultiplexer-提供block waiting,直到在handle set中有任何event的發生
-指示說某個operation可以被呼叫而且不會有任何的blocking
Event Handler
-定義一個處理indication event的共有介面
Concrete Event Handler
-Event Handler的實作,根據程式的邏輯來處理event。
Reactor
-可以register或remove一個event handler
-管理handle set
-執行application的event loop。
Dynamics

1. 首先Main Program先向Reactor註冊Event Handler
2. 而Reactor會呼叫Synchronous Event Demultiplexer的select此blocking method。
3. 當一個或多個event source有任何indication event產生時,select會回傳。
4. 針對產生的event分派給對應的的event handler。
Consequences
此pattern在很多的場合都會看到蹤跡,最常見的就是non-blocking io的select此method,有寫過berkeley socket的人應該很有感覺。但是更不一樣的是此pattern把處理某個event的邏輯抽離出來,委託給應用程式去實作,這是一種"inversion of control"的一種實現。
在java中,J2SE 1.4開始也有了select此method的支援,
分別是用到
java.nio.channles.Selector
java.nio.channels.SelectableSocket
java.nio.channels.SelectionKey
有關實作此pattern的細節可以參考Doug Lea的投影片
http://www.jsptw.com/jute/post/view?bid=12&id=12075&sty=1&tpg=1&age=0
至於此pattern最大的兩個優點我認為是
Coarse-grained concurrency control:
此pattern用一個thread(或process)去處理很多個concurrency,這會大大的減少thread的產生,以及避免複雜的synchronization。
Separartion of concerns:
此pattern把底層demultiplex跟dispatch的機制,跟application-specific service implemenation完全的抽離。如此可以減少application本身的複雜度,同時也增加了整個架構的重複使用性。
但是也有一些缺點
Non-pre-emptive:
若某個handler把thread佔去去做一個很花時間的動作,那整個系統的效能將會被拖垮。此問題可以把task委託給其他thread處理而獲得解決。
Complexity of debugging and testing:
這個問題主要來自reactor pattern是使用"inversion of control",所以的event handler都是透過callback的方式被喚起,所以無法從頭到尾追蹤錯誤的來源。除此之外,若兩個event之間有State的關係,此種程式會更難撰寫。
Introduction
Extension Interface這個design pattern允許元件提供數個介面。會這樣的設計主要是因為當元件不斷的開發的時候,我們不改變舊有的介面;相對的,我們提供新的介面,以免舊有的介面不斷膨脹,甚至影響原有client的正確性。
Context
元件的介面可能不斷開發演進的應用程式環境。
Problem
在應付時常改變的程式需求時,元件所提供的介面可能時常需要修改或是擴充以滿足新功能的要求。若是元件在release之前,我們可以預料需求的改變的話,我們可以用"里斯可夫取代法則(Liskov Substitution Principle)"來選擇適當的base interface允許他的method由子類別去擴充其功能性。
但是有時候我們的元件已經釋出了,之後的改變是我們無法預期的。若元件已經整合在數個應用程式之中,我們還需要增加或修改元件的需求時,修改元件的功夫將需要更加的謹慎。首先我們必須要求不會破壞到使用舊元件的應用程式;再者,新功能可能是在少數應用才會使用到,若一味的增加新功能而讓元件使用者使用該元件過於複雜,也不是很好的結果。
Solution
我們提供元件使用者用不同的介面來存取同一個元件。而每個介面代表的是元件所扮演的一種角色,而非所有角色都透過同一個介面來使用。換言之,我們若想要提供一個元件一個新的功能(或說扮演一個新的角色),我們不改變暨有的元件介面,相對的,我們為此元件增加一個新的介面來使用這個新的功能。
Structure

Participants and Responsibilities
Copomnent
1. 扮演不同的角色
2. 實作extension interfaces
3. 回傳root interface給component factory
Root Interface
1. 定義所有extension interface所需要的最基本的功能
Extension Interface
1. 定義元件所提供"角色特有"的介面
Client
1. 透過Component Factory產生元件
2. 使用extension interface來存取元件所提供的功能
Component Factory
1. 定義產生元件所需的功能
2. (選用) 定義找尋已存在的component所需的功能
Dynamics
在此,我們有兩種scenario來使用extension interface pattern。
Scenario I
1. client向component factory要求傳回元件的特定介面。
2. 此時component factory產生一個新的component,並且取得roote interface的reference。
3. component factory再透過initial interface來取得extension interface,並且回傳給client

Scenario II
1. client使用extension interface A的某一個method,在此不管他是root或是extension的 interface。
2. component回傳此method的結果。
3. client呼叫getExtension(),並且取得另一個他所感興趣的interface。由於所有的extension interface都是繼承root interface,所以必定有getExtension()此method。
4. client取得extension inteface B後,呼叫extension interface B的某個method。

Known Uses
事實上很明顯的,這個pattern讓人直接想到微軟的COM。root interface就是IUnknown,而getExtension就是IUnknown中QueryInterface這個method。在COM中透過128bit的GUID來代表某一個InterfaceID(或稱IID)。所以若有學過COM的人看此pattern會非常的直覺。
Consequences
優點:
Extensibility
Separation of concerns
Decoupling of components and their client
Support for interface aggregation and delegation
缺點:
Increased component design and implementation effort
Increased client programming complexity
Additional indirection and run-time overhead
Introduction
Interceptor是一個Architectural Pattern。此pattern允許某個service在不影響原有架構下加入framework中,並且當事件發生觸發對應的service處理事件。
Context
可以在不影響架構之下擴充功能的framework。
Problem
1. 一個framework應該允許在不改變核心程式的前提下,整合進額外的服務。
2. 當我們要整合程式特有(application-specific)的service時,理應不用動到既有的 framework元件,也應該改變到使用此framework的應用程式。
3. 使用framework的應用程式也許會需要監測及控制他自己的行為。
Solution
由於要允許應用程式額外註冊一個service,因此我們必須先定義好一個service應有的介面,稱此介面為interceptor。應用程式則根據interceptor介面實作一個concrete interceptor,並且跟concrete framework註冊。當事件發生時,concrete framework透過dispatcher找到適當的concreate interceptor做事件回呼(event callback),並且傳入context object以提供conrete framework的run-time資訊。
structure

participants and responsibilities
Concrete framework:
-提供應用程式服務
-整合dispatchers以分派event到interceptor
-委派event到對應的dispatcher
Interceptor
-定義service所應有的介面
Concrete Interceptor
-實作interceptor的service
-使用context object去控制concrete framework
Dispatcher
-允許應用程式去註冊或是移除concrete interceptor
-當event發生時,負責分派對對應的concrete interceptor
Context Objects
-允許service存取concrete framework中的資訊
-允許service去控制concreate framework中的行為
dynamcis

conclusions
事實上在Servlet, EJB, Applet都是使用這種pattern
例如HttpServlet就是一個interceptor
我門實作的Servlet就是一個Concrete interceptor
ServletContext就是Context Object
Dispatcher是存在Servlet Container中,負責把某個URL對應到某個Servlet
當然,一個Servlet Container就是一個concrete framework
由此就可以清楚了解interceptor的精隨了
Introduction
Component Configurator這個pattern主要的目的是允許程式在run-time的時候可以安裝或是移除某個component。程式可以不用修改、重新編譯、靜態鏈結(statically relink)。甚至在更理想的狀況下,可以重新安裝一個元件在已經執行的process之上,而不用停止及重新啟動這已經執行的程式。
Context
當我們需要開發的componont,能夠在被initiated, suspended, resumed, terminated這些動作時,越具有彈性(flexibility)越好,並且具有通透性(transparency)。
Problem
1.程式的實作常常會需要改變。
2.程式在開發的過程中我們不會知道最好的實作方式,若一開始就定死某種實作則會大大失去彈性。
3.分散各處的component我們需要一個centralized的管理機制。管理者絕對不希望每個host上的component都要有一個管理程式。
Solution
為了達到可以隨時抽換的功能,所以我們必須降低介面跟實作的耦合性。因此我們必須定義component的介面,以在安裝component到application時,application所使用的API跟任何的實作獨立。之後我們必須時作concrete componets為真正的實作,他必須實作component介面所定義的init(), fini(), suspend(), resume(), terminate(),並且包裝成可以動態鏈結的形式,如windows下的dll(在java中可以包成jar檔,並且用ClassLoader來讀取最新的Component)。而這些dll(或是jar)透過component configurator動態鏈結(在java是動態載入dynamic loading)的方式讀入component的資料,並且存放在component repository。
Structure

Participant
Component: 定義Component應有的介面,如init(), fini(), resume(), suspend(), terminate()...
ConcreteComponent: 實作一個可以動態安裝的application component
ComponentConfigurator: 負責掌管安裝、移除component。
ComponentRepository: 維護應用程式中的component。
dynamic

Implementation
1. 定義component的介面。
2. 實作component repository,需要有一些insert(), remove(), find()等功能。
3. 定義component configurator介面。這邊書上有建議我們可以定義一套directive的方式來操作configurator的功能,因此必須定義有這些directive的format,以及實作parser等。另外還要實作有關動態鏈結的邏輯。因此這一部分會花上很大的功夫。
4. 實作concrete component,撰寫各元件的邏輯。書上提到實作component上需要考慮的問題,其中包跨concurrent model,是只允許single thread,還是允許multithread呢。還有是否支援inter-component communication呢?還有可不可以允許component之間有relationship呢?這些都可以考慮進去。
Known Uses
1. Windows NT Service Control Manager.
2. Modern operating system device driver.
3. JMX。這個我必須多說明一下,事實上使用JMX就是解決這個問題的一個很好的solution。這裡的component就是JMX的MBean,component repository就是在MBeanServer裡,component configurator可以使用MLet的方式做dynamic loading。而centralized的management可以透過http方式去管理,或是透過JSR#160的JMX Remote來完成。
Consequences
其實在java中要實作這個pattern有得天獨厚的優勢就是dynamic loading,所有的class都是透過ClassLoader方式讀入,所以光這點就很好實作此pattern。另外此pattern可以跟GoF strategy pattern跟bridge pattern做個比較,找出這兩個pattern跟此pattern的差異。
Instroduction
Wrapper Facade pattern主要是用來包裝已經存在的non-object-oriented的API,通常是OS題供的system call,以成為一個object-oriented的api。此方法可以讓API使用起來較為簡單、穩固、增加可攜性、並且更具有凝聚力的object-oriented的程式介面。
Context
開發中的程式必須使用到系統中提供的一些common mechanism或是service。但是這些服務是以non-object-oriented的方式呈現。
Problem
不好撰寫,non-OO的程式通常很瑣碎。
跟平台綁死,不portable。
就算可以portable,還必須用很多directives,程式更難維護。
non-OO的程式通常都不high cohesive。我們永遠不知道哪些function之間是相關的。
Solution
一言以蔽之,"包起來"。這就是Wrapper Facade的精隨。我們以OO的方式把底層所有的system call或是non-oo library全部給包起來,此層稱為Wrapper Facade,此好處是把原有醜陋的non-OO API,變成簡單易用的OO API。除此之外我們也可以把跟OS-denpendent的部分抽象出來變成一致的OS-Independent的介面,如此以達到跨平台的目的。
Known Uses
MFC: 把醜陋的Win32 Platform SDK包裝起來。
ACE(Adaptive Communication Environment): 他把很多平台的service包裝成一致的Wrapper Facade。如Socket,thread,mutex等。
JAVA: 事實上就是一個Wrapper Facade。