怎樣設計合適的介面(2) (轉)

worldblog發表於2007-12-09
怎樣設計合適的介面(2) (轉)[@more@]怎樣設計合適的介面(2)

[ 作者: 李煒   新增時間: 2001-9-3 8:06:50 ]


為了解決問題,也需要由類的使用者而不是類的設計者來完成:
class EventExample{
public void example(Event event, Handler newHandler){
synchronized(eventSource){
oldHandler = eventSource.getHandler(event);
eventSource.installHandler(event, newHandler);
}
}
private EventSource eventSource;
private Handler oldHandler;
}




我們假設:目標eventSource是的,每一個方法體的時間和通訊的延遲相比是很短的。在這個例子中,eventSource的方法被了兩次,並可能在其他的例項中重複多次,因而,開銷也是至少兩倍。

此外還有一個問題是對外部的synchronized同步塊的使用需求。對synchronized塊的使用之所以會失敗,主要因為我們透過物件來完成工作,所以,呼叫者的synchronized塊,同步的是代理物件而不是最終的目標物件,呼叫者不可能對其行為做太多的保證。

Combined Method必須在分佈的環境,或者,執行緒環境中同時執行。它反映了直接的應用,恢復策略和一些笨拙的方法被封裝到Combined Method中,並簡化了介面,減少了介面中不需要的累贅。Combined Method的效果是支援一種更像事務處理風格的設計。

在一個組合的Command-Query中提供一個單獨的Query方法通常是合理的。提供分離的Command方法是不太常見的,因為Combined Method可以完成這一工作,只要呼叫者簡單的忽略返回結果。如果返回一個結果招致一個開銷的話,才可能會提供一個單獨的Command方法。

回到前一個例子中,如果installHandler method返回上一次的控制程式碼,則設計變得更加簡單和獨立:
interface EventSource{
Handler installHandler(Event event, Handler newHandler);
}




客戶程式碼如下:
class EventSourceExample{
public void example(Event event, Handler newHandler){
oldHandler = eventSource.installHandler(event, newHandler);
}
private EventSource eventSource;
private Handler oldHandler;
}



這樣,我們給呼叫者提供了一個更加的介面,並且不再需要他們解決執行緒的問題。從而降低了風險和程式碼量,將類設計的職責全部給了類設計者而不是推給使用者,即使有代理物件的出現也不會影響到正確性。

一個Combined Method可以是許多Query的集合,許多Command的集合,或者兩者兼有。這樣,它可能補充Command、Query方法,也可能與之相牴觸。當衝突發生的時候,優先選擇Combined Method會產生一個不同的正確性和適用性。

在另一個例子中,我們考慮獲得資源的情況。假設,在下面的介面中,方法acquire在資源可用前阻塞:
interface Resource{
boolean isAcquired();
void acquire();
void release();
}



類似於下面的程式碼會在一個執行緒中推薦使用:
class ResourceExample{
public void example(){
boolean acquired = false;
synchronized(resource){
if(!resource.isAcquired())
resource.acquire();
else
acquired = true;
}
if(!acquired)
...
}
private Resource resource;
}



然而,即使我們放棄可讀性和易用性,這樣的設計也不是一個Command-Query分離的設計。如果引入了代理,它就會失敗:
class ActualResource implements Resource {...}
class Resource implements Resource {...}




如果使用者既可以透過ActualResource來完成工作,也可以透過ResourceProxy來完成工作,而且,ActualResource和ResourceProxy都沒有處理同步,則synchronized塊可能會失敗。因為,既然我們可以透過代理物件ResourceProxy來完成工作,那麼,呼叫者的synchronized塊,同步的就是代理物件ResourceProxy而不是最終的目標物件ActualResource。

一個Combined Method解決了這個問題,它使併發和間接性更加透明。
interface Resource{
boolean tryAcquire();
}

下面的程式碼清晰、簡單並且正確:
class ResourceExample{
public void example(){
if(!resource.tryAcquire())
...
}
private Resource resource;
}


Combined Method帶來的一個結果是使一些測試和基於斷言的設計變得十分笨拙,然而,它適合解決執行緒和分佈問題。

實際應用中,介面應該單一化還是複合化,要視具體情況而定。

關於作者
李煒:北京傑合偉業公司產品技術部經理。1996年四川大學系本科畢業,5年,主要從事基於INTE的B/S結構的開發,專長為、物件導向技術等。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990125/,如需轉載,請註明出處,否則將追究法律責任。

相關文章