真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JAVA中如何設(shè)計(jì)合適的接口

這篇文章主要介紹JAVA中如何設(shè)計(jì)合適的接口,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括鎮(zhèn)安網(wǎng)站建設(shè)、鎮(zhèn)安網(wǎng)站制作、鎮(zhèn)安網(wǎng)頁制作以及鎮(zhèn)安網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,鎮(zhèn)安網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到鎮(zhèn)安省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

我們在設(shè)計(jì)系統(tǒng)接口時(shí),經(jīng)常會遇到這樣的問題:

我們的接口應(yīng)該提供多少方法才合適?

我們的接口應(yīng)該提供"原子方法"還是"復(fù)合方法"?

我們的接口是否應(yīng)該封裝(或者,能否封裝)所有的細(xì)節(jié)?

接口的設(shè)計(jì)需要考慮用戶的使用習(xí)慣、使用的方便程度、使用的安全程度,根據(jù)我的編程經(jīng)驗(yàn),下面會詳細(xì)討論接口設(shè)計(jì)的2個(gè)需要權(quán)衡的方面:接口的單一化 & 復(fù)合化。


接口

接口提供了不同系統(tǒng)之間或者系統(tǒng)不同組件之間的界定。在軟件中,接口提供了一個(gè)屏障,從而從實(shí)現(xiàn)中分離目標(biāo),從具體中分離抽象,從作者中分離用戶。

站在用戶的角度看,一個(gè)接口建立并命名了一個(gè)目標(biāo)對象的使用方法。一些約束(例如:編譯時(shí)的類型系統(tǒng)、運(yùn)行時(shí)的異常機(jī)制及返回值)使得類作者的目的得以體現(xiàn)和加強(qiáng)。供給(affordances)指事物的被感知的真實(shí)的屬性,這些屬性可以決定事物使用的可能方法,供給提供了對事物操作的線索。

類設(shè)計(jì)者的一個(gè)職責(zé)便是在接口中減小約束與供給之間的隔閡、匹配目標(biāo)以及一定程度上的自由度,盡可能減小錯(cuò)誤使用目標(biāo)對象的可能。


封裝

對于封裝來說,遠(yuǎn)不止數(shù)據(jù)私有那么簡單。在設(shè)計(jì)中,封裝往往會涉及到自我包含(self-containment)。如果一個(gè)類需要你知道如何調(diào)用它方法(e.g. 在一個(gè)線程的環(huán)境中,在一個(gè)方法調(diào)用后調(diào)用另一個(gè)方法,你必須明確地同步對象),那么它的封裝性就不如將所有這些全部包含并隱藏的類(e.g. 這個(gè)類是thread-safe的)好。前一個(gè)設(shè)計(jì)存在著設(shè)計(jì)的漏洞,它的許多限定條件是模糊的,而且把部分責(zé)任推給了用戶,而不是讓類提供者做這些工作來完成類的設(shè)計(jì)。

在空間或者時(shí)間上分離方法的執(zhí)行(例如,線程,遠(yuǎn)程方法調(diào)用,消息隊(duì)列),能夠?qū)υO(shè)計(jì)的正確性和效率產(chǎn)生意義深遠(yuǎn)的影響。這種分離帶來的結(jié)果是不可忽視的:

并發(fā)引入了不確定性和環(huán)境(context)選擇的開銷;

分布引入了回調(diào)的開銷,這些開銷可能不斷增加,而且會導(dǎo)致錯(cuò)誤。

這些是設(shè)計(jì)的問題,修改它們可不是象修改bug那樣簡單。

如果一個(gè)接口主要由存取方法(set和get方法)組成,每個(gè)方法都相應(yīng)的直接指向某個(gè)私有域,那么它的封裝性會很差。接口中的域存取方法通常是不會提供信息的:他們在對象的使用中不能通訊、簡單化和抽象化,這通常會導(dǎo)致代碼冗長,并且容易出錯(cuò)。

所以,我們首先考慮接口設(shè)計(jì)的第一個(gè)原則:

命令與查詢分離(Command-Query Separation)

要求:保證一個(gè)方法不是命令(Command)就是查詢(Query)

定義:
查詢:當(dāng)一個(gè)方法返回一個(gè)值來回應(yīng)一個(gè)問題的時(shí)候,它就具有查詢的性質(zhì);

命令:當(dāng)一個(gè)方法要改變對象的狀態(tài)的時(shí)候,它就具有命令的性質(zhì);

通常,一個(gè)方法可能是純的Command模式或者是純的Query模式,或者是兩者的混合體。在設(shè)計(jì)接口時(shí),如果可能,應(yīng)該盡量使接口單一化,保證方法的行為嚴(yán)格的是命令或者是查詢,這樣查詢方法不會改變對象的狀態(tài),沒有副作用(side effects),而會改變對象的狀態(tài)的方法不可能有返回值。也就是說:如果我們要問一個(gè)問題,那么就不應(yīng)該影響到它的答案。實(shí)際應(yīng)用,要視具體情況而定,語義的清晰性和使用的簡單性之間需要權(quán)衡。

例如,在java.util.Iterator中,hasNext可以被看作一種查詢,remove是一種命令,next合并了命令和查詢:

public interface Iterator{boolean hasNext();Object next();void remove();}

這里,如果不將一個(gè)Iterator對象的當(dāng)前值向前到下一個(gè)的話,就不能夠查詢一個(gè)Iterator對象。如果沒有提供一個(gè)復(fù)合方法next,我們將需要定義一系列的命令方法,例如:初始化(initialization)、繼續(xù)(continuation)、訪問(access)和前進(jìn)(advance),它們雖然清晰定義了每個(gè)動(dòng)作,但是,客戶代碼過于復(fù)雜:

for(initialization; continuation condition; advance){... access for use ...}

將Command和Query功能合并入一個(gè)方法,方便了客戶的使用,但是,降低了清晰性,而且,可能不便于基于斷言的程序設(shè)計(jì)并且需要一個(gè)變量來保存查詢結(jié)果:

Iterator iterator = collection.iterator();while(iterator.hasNext();){Object current = iterator.next();... use current...}

下面,我們考慮接口設(shè)計(jì)的第二個(gè)原則:

組合方法(Combined Method)

組合方法經(jīng)常在線程和分布環(huán)境中使用,來保證正確性并改善效率。

一些接口提供大量的方法,起初,這些方法看來是最小化的,而且相關(guān)性強(qiáng)。然而,在使用的過程中,一些接口顯現(xiàn)得過于原始,它們過于簡單化,從而迫使類用戶用更多的工作來實(shí)現(xiàn)普通的任務(wù),并且,方法之間的先后順序及依賴性比較強(qiáng)(即,暫時(shí)耦合)。這導(dǎo)致了代碼重復(fù),而且非常麻煩和容易出錯(cuò)。

一些需要同時(shí)執(zhí)行成功的方法,在多線程、異常、和分布的情況下會遇到麻煩。如果兩個(gè)動(dòng)作需要同時(shí)執(zhí)行,它們由兩個(gè)獨(dú)立的方法進(jìn)行描述,必須都完全成功的執(zhí)行,否則會導(dǎo)致所有動(dòng)作的回滾。

線程的引入使這種不確定性大大增加。一系列方法同時(shí)調(diào)用一個(gè)易變的(mutable)對象,如果這個(gè)對象在線程之間共享,即使我們假設(shè)單獨(dú)的方法是線程安全的,也無法確保結(jié)果是意料之中的??聪旅鎸vent Source的接口,它允許安置句柄和對事件的查詢:

interface EventSource{Handler getHandler(Event event);void installHandler(Event event, Handler newHandler);}

線程之間的交叉調(diào)用可能會引起意想不到的結(jié)果。假設(shè)source域引用一個(gè)線程共享的對象,對象很可能在1、2之間被另一個(gè)線程安裝了一個(gè)新的句柄:

class EventSourceExample{public void example(Event event, Handler newHandler){oldHandler = eventSource.getHandler(event); // 1//對象很可能在這里被另一個(gè)線程安裝了一個(gè)新的句柄eventSource.installHandler(event, newHandler); // 2}private EventSource eventSource;private Handler oldHandler;}

為了解決問題,也需要由類的使用者而不是類的設(shè)計(jì)者來完成:

class EventSourceExample{public void example(Event event, Handler newHandler){synchronized(eventSource){oldHandler = eventSource.getHandler(event);eventSource.installHandler(event, newHandler);}}private EventSource eventSource;private Handler oldHandler;}

我們假設(shè):目標(biāo)對象eventSource是遠(yuǎn)程的,執(zhí)行每一個(gè)方法體的時(shí)間和通訊的延遲相比是很短的。在這個(gè)例子中,eventSource的方法被調(diào)用了兩次,并可能在其他的實(shí)例中重復(fù)多次,因而,開銷也是至少兩倍。

此外還有一個(gè)問題是對外部的synchronized同步塊的使用需求。對synchronized塊的使用之所以會失敗,主要因?yàn)槲覀兺ㄟ^代理對象來完成工作,所以,調(diào)用者的synchronized塊,同步的是代理對象而不是最終的目標(biāo)對象,調(diào)用者不可能對其行為做太多的保證。

Combined Method必須在分布的環(huán)境,或者,線程環(huán)境中同時(shí)執(zhí)行。它反映了用戶直接的應(yīng)用,恢復(fù)策略和一些笨拙的方法被封裝到Combined Method中,并簡化了接口,減少了接口中不需要的累贅。Combined Method的效果是支持一種更像事務(wù)處理風(fēng)格的設(shè)計(jì)。

在一個(gè)組合的Command-Query中提供一個(gè)單獨(dú)的Query方法通常是合理的。提供分離的Command方法是不太常見的,因?yàn)镃ombined Method可以完成這一工作,只要調(diào)用者簡單的忽略返回結(jié)果。如果返回一個(gè)結(jié)果招致一個(gè)開銷的話,才可能會提供一個(gè)單獨(dú)的Command方法。

回到前一個(gè)例子中,如果installHandler method返回上一次安裝的句柄,則設(shè)計(jì)變得更加簡單和獨(dú)立:

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;}

這樣,我們給調(diào)用者提供了一個(gè)更加安全的接口,并且不再需要他們解決線程的問題。從而降低了風(fēng)險(xiǎn)和代碼量,將類設(shè)計(jì)的職責(zé)全部給了類設(shè)計(jì)者而不是推給用戶,即使有代理對象的出現(xiàn)也不會影響到正確性。

一個(gè)Combined Method可以是許多Query的集合,許多Command的集合,或者兩者兼有。這樣,它可能補(bǔ)充Command、Query方法,也可能與之相抵觸。當(dāng)沖突發(fā)生的時(shí)候,優(yōu)先選擇Combined Method會產(chǎn)生一個(gè)不同的正確性和適用性。

在另一個(gè)例子中,我們考慮獲得資源的情況。假設(shè),在下面的接口中,方法acquire在資源可用前阻塞:

interface Resource{boolean isAcquired();void acquire();void release();}

類似于下面的代碼會在一個(gè)線程系統(tǒng)中推薦使用:

class ResourceExample{public void example(){boolean acquired = false;synchronized(resource){if(!resource.isAcquired())resource.acquire();elseacquired = true;}if(!acquired)...}private Resource resource;}

然而,即使我們放棄可讀性和易用性,這樣的設(shè)計(jì)也不是一個(gè)Command-Query分離的設(shè)計(jì)。如果引入了代理,它就會失敗:

class ActualResource implements Resource {...}class ResourceProxy implements Resource {...}

如果用戶既可以通過ActualResource來完成工作,也可以通過ResourceProxy來完成工作,而且,ActualResource和ResourceProxy都沒有處理同步,則synchronized塊可能會失敗。因?yàn)?,既然我們可以通過代理對象ResourceProxy來完成工作,那么,調(diào)用者的synchronized塊,同步的就是代理對象ResourceProxy而不是最終的目標(biāo)對象ActualResource。

一個(gè)Combined Method解決了這個(gè)問題,它使并發(fā)和間接性更加透明。

interface Resource{

boolean tryAcquire();

}

下面的代碼清晰、簡單并且正確:

class ResourceExample{public void example(){if(!resource.tryAcquire())...}private Resource resource;}

Combined Method帶來的一個(gè)結(jié)果是使一些測試和基于斷言的程序設(shè)計(jì)變得十分笨拙,然而,它適合解決線程和分布問題。

實(shí)際應(yīng)用中,接口應(yīng)該單一化還是復(fù)合化,要視具體情況而定。

以上是“JAVA中如何設(shè)計(jì)合適的接口”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


分享題目:JAVA中如何設(shè)計(jì)合適的接口
瀏覽路徑:http://weahome.cn/article/iecihs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部