面向介面程式設計講解

2023-02-11 03:33:05 字數 4950 閱讀 7799

1.面向介面程式設計和物件導向程式設計是什麼關係

首先,面向介面程式設計和物件導向程式設計並不是平級的,它並不是比物件導向程式設計更先進的一種獨立的程式設計思想,而是附屬於物件導向思想體系,屬於其一部分。或者說,它是物件導向程式設計體系中的思想精髓之一。

2.介面的本質

介面,在表面上是由幾個沒有主體**的方法定義組成的集合體,有唯一的名稱,可以被類或其他介面所實現(或者也可以說繼承)。它在形式上可能是如下的樣子:

inte***ceinte***cename

那麼,介面的本質是什麼呢?或者說介面存在的意義是什麼。我認為可以從以下兩個視角考慮:

1)介面是一組規則的集合,它規定了實現本介面的類或介面必須擁有的一組規則。體現了自然界「如果你是……則必須能……」的理念。

例如,在自然界中,人都能吃飯,即「如果你是人,則必須能吃飯」。那麼模擬到電腦程式中,就應該有乙個iperson(習慣上,介面名由「i」開頭)介面,並有乙個方法叫eat(),然後我們規定,每乙個表示「人」的類,必須實現iperson介面,這就模擬了自然界「如果你是人,則必須能吃飯」這條規則。

從這裡,我想各位也能看到些許物件導向思想的東西。物件導向思想的核心之一,就是模擬真實世界,把真實世界中的事物抽象成類,整個程式靠各個類的例項互相通訊、互相協作完成系統功能,這非常符合真實世界的執行狀況,也是物件導向思想的精髓。

2)介面是在一定粒度檢視上同類事物的抽象表示。注意這裡我強調了在一定粒度檢視上,因為「同類事物」這個概念是相對的,它因為粒度檢視不同而不同。

例如,在我的眼裡,我是乙個人,和一頭豬有本質區別,我可以接受我和我同學是同類這個說法,但絕不能接受我和一頭豬是同類。但是,如果在乙個動物學家眼裡,我和豬應該是同類,因為我們都是動物,他可以認為「人」和「豬」都實現了ianimal這個介面,而他在研究動物行為時,不會把我和豬分開對待,而會從「動物」這個較大的粒度上研究,但他會認為我和一棵樹有本質區別。

現在換了乙個遺傳學家,情況又不同了,因為生物都能遺傳,所以在他眼裡,我不僅和豬沒區別,和乙隻蚊子、乙個細菌、一顆樹、乙個蘑菇乃至乙個sars病毒都沒什麼區別,因為他會認為我們都實現了idescendable這個介面(注:descendvi. 遺傳),即我們都是可遺傳的東西,他不會分別研究我們,而會將所有生物作為同類進行研究,在他眼裡沒有人和病毒之分,只有可遺傳的物質和不可遺傳的物質。

但至少,我和一塊石頭還是有區別的。

可不幸的事情發生了,某日,地球上出現了一位偉大的人,他叫列寧,他在熟讀馬克思、恩格斯的辯證唯物主義思想巨著後,頗有心得,於是他下了乙個著名的定義:所謂物質,就是能被意識所反映的客觀實在。至此,我和一塊石頭、一絲空氣、一條成語和傳輸手機訊號的電磁場已經沒什麼區別了,因為在列寧的眼裡,我們都是可以被意識所反映的客觀實在。

如果列寧是一名程式設計師,他會這麼說:所謂物質,就是所有同時實現了「ireflectabe」和「iesse」兩個介面的類所生成的例項。(注:

reflect v. 反映 esse n. 客觀實在)

也許你會覺得我上面的例子像在瞎掰,但是,這正是介面得以存在的意義。物件導向思想和核心之一叫做多型性,什麼叫多型性?說白了就是在某個粒度檢視層面上對同類事物不加區別的對待而統一處理。

而之所以敢這樣做,就是因為有介面的存在。像那個遺傳學家,他明白所有生物都實現了idescendable介面,那只要是生物,一定有descend()這個方法,於是他就可以統一研究,而不至於分別研究每一種生物而最終累死。

可能這裡還不能給你乙個關於介面本質和作用的直觀印象。那麼在後文的例子和對幾個設計模式的解析中,你將會更直觀體驗到介面的內涵。

3.面向介面程式設計綜述

通過上文,我想大家對介面和介面的思想內涵有了乙個了解,那麼什麼是面向介面程式設計呢?我個人的定義是:在系統分析和架構中,分清層次和依賴關係,每個層次不是直接向其上層提供服務(即不是直接例項化在上層中),而是通過定義一組介面,僅向上層暴露其介面功能,上層對於下層僅僅是介面依賴,而不依賴具體類。

這樣做的好處是顯而易見的,首先對系統靈活性大有好處。當下層需要改變時,只要介面及介面功能不變,則上層不用做任何修改。甚至可以在不改動上層**時將下層整個替換掉,就像我們將乙個wd的60g硬碟換成乙個希捷的160g的硬碟,計算機其他地方不用做任何改動,而是把原硬碟拔下來、新硬碟插上就行了,因為計算機其他部分不依賴具體硬碟,而只依賴乙個ide介面,只要硬碟實現了這個介面,就可以替換上去。

從這裡看,程式中的介面和現實中的介面極為相似,所以我一直認為,介面(inte***ce)這個詞用的真是神似!

使用介面的另乙個好處就是不同部件或層次的開發人員可以並行開工,就像造硬碟的不用等造cpu的,也不用等造顯示器的,只要介面一致,設計合理,完全可以並行進行開發,從而提高效率。

本篇文章先到這裡。最後我想再囉嗦一句:物件導向的精髓是模擬現實,這也可以說是我這篇文章的靈魂。所以,多從現實中思考物件導向的東西,對提高系統分析設計能力大有脾益。

下篇文章,我將用乙個例項來展示介面程式設計的基本方法。

而第三篇,我將解析經典設計模式中的一些面向介面程式設計思想,並解析一下.net分層架構中的面向介面思想。

對本文的補充:

仔細看了各位的回覆,非常高興能和大家一起討論技術問題。感謝給出肯定的朋友,也要感謝提出意見和質疑的朋友,這促使我更深入思考一些東西,希望能藉此進步。在這裡我想補充一些東西,以討論一些回覆中比較集中的問題。

1.關於「面向介面程式設計」中的「介面」與具體物件導向語言中「介面」兩個詞

看到有朋友提出「面向介面程式設計」中的「介面」二字應該比單純程式語言中的inte***ce範圍更大。我經過思考,覺得很有道理。這裡我寫的確實不太合理。

我想,物件導向語言中的「介面」是指具體的一種**結構,例如c#中用inte***ce關鍵字定義的介面。而「面向介面程式設計」中的「介面」可以說是一種從軟體架構的角度、從乙個更抽象的層面上指那種用於隱藏具體底層類和實現多型性的結構部件。從這個意義上說,如果定義乙個抽象類,並且目的是為了實現多型,那麼我認為把這個抽象類也稱為「介面」是合理的。

但是用抽象類實現多型合理不合理?在下面第二條討論。

概括來說,我覺得兩個「介面」的概念既相互區別又相互聯絡。「面向介面程式設計」中的介面是一種思想層面的用於實現多型性、提高軟體靈活性和可維護性的架構部件,而具體語言中的「介面」是將這種思想中的部件具體實施到**裡的手段。

2.關於抽象類與介面

看到回覆中這是討論的比較激烈的乙個問題。很抱歉我考慮不周沒有在文章中討論這個問題。我個人對這個問題的理解如下:

如果單從具體**來看,對這兩個概念很容易模糊,甚至覺得介面就是多餘的,因為單從具體功能來看,除多重繼承外(c#,j**a中),抽象類似乎完全能取代介面。但是,難道介面的存在是為了實現多重繼承?當然不是。

我認為,抽象類和介面的區別在於使用動機。使用抽象類是為了**的復用,而使用介面的動機是為了實現多型性。所以,如果你在為某個地方該使用介面還是抽象類而猶豫不決時,那麼可以想想你的動機是什麼。

看到有朋友對iperson這個介面的質疑,我個人的理解是,iperson這個介面該不該定義,關鍵看具體應用中是怎麼個情況。如果我們的專案中有women和man,都繼承person,而且women和man絕大多數方法都相同,只有乙個方法dosomethinginwc()不同(例子比較粗俗,各位見諒),那麼當然定義乙個abstractperson抽象模擬較合理,因為它可以把其他所有方法都包含進去,子類只定義dosomethinginwc(),大大減少了重複**量。

但是,如果我們程式中的women和man兩個類基本沒有共同**,而且有乙個personhandle類需要例項化他們,並且不希望知道他們是男是女,而只需把他們當作人看待,並實現多型,那麼定義成介面就有必要了。

總而言之,介面與抽象類的區別主要在於使用的動機,而不在於其本身。而乙個東西該定義成抽象類還是介面,要根據具體環境的上下文決定。

再者,我認為介面和抽象類的另乙個區別在於,抽象類和它的子類之間應該是一般和特殊的關係,而介面僅僅是它的子類應該實現的一組規則。(當然,有時也可能存在一般與特殊的關係,但我們使用介面的目的不在這裡)如,交通工具定義成抽象類,汽車、飛機、輪船定義成子類,是可以接受的,因為汽車、飛機、輪船都是一種特殊的交通工具。再譬如icomparable介面,它只是說,實現這個介面的類必須要可以進行比較,這是一條規則。

如果car這個類實現了icomparable,只是說,我們的car中有乙個方法可以對兩個car的例項進行比較,可能是比哪輛車更貴,也可能比哪輛車更大,這都無所謂,但我們不能說「汽車是一種特殊的可以比較」,這在文法上都不通。

問題的提出

定義:現在我們要開發乙個應用,模擬移動儲存裝置的讀寫,即計算機與u盤、***、行動硬碟等裝置進行資料交換。

上下文(環境):已知要實現u盤、*****器、行動硬碟三種移動儲存裝置,要求計算機能同這三種裝置進行資料交換,並且以後可能會有新的第三方的移動儲存裝置,所以計算機必須有擴充套件性,能與目前未知而以後可能會出現的儲存裝置進行資料交換。各個儲存裝置間讀、寫的實現方法不同,u盤和行動硬碟只有這兩個方法,***player還有乙個playmusic方法。

名詞定義:資料交換=

看到上面的問題,我想各位腦子中一定有了不少想法,這是個很好解決的問題,很多方案都能達到效果。下面,我列舉幾個典型的方案。

解決方案列舉

方案一:分別定義flashdisk、***player、mobileharddisk三個類,實現各自的read和write方法。然後在computer類中例項化上述三個類,為每個類分別寫讀、寫方法。

例如,為flashdisk寫readfromflashdisk、writetoflashdisk兩個方法。總共六個方法。

方案二:定義抽象類mobilestorage,在裡面寫虛方法read和write,三個儲存裝置繼承此抽象類,並重寫read和write方法。computer類中包含乙個型別為mobilestorage的成員變數,並為其編寫get/set器,這樣computer中只需要兩個方法:

readdata和writedata,並通過多型性實現不同移動裝置的讀寫。

方案三:與方案二基本相同,只是不定義抽象類,而是定義介面imobilestorage,移動儲存器類實現此介面。computer中通過依賴介面imobilestorage實現多型性。

方案四:定義介面ireadable和iwritable,兩個介面分別只包含read和write,然後定義介面imobilestorage介面繼承自ireadable和iwritable,剩下的實現與方案三相同。

物件導向程式設計與面向過程程式設計

面向過程程式設計都會把程式 放在main 裡面。對於物件導向程式設計,我們就是離開過程化的世界,將事物抽象成物件,對物件的屬性抽象成變數,動作 行為等抽象成方法。就像自然界一樣,子代繼承父輩的屬性和方法 同時介面可以更靈活的重寫多個類的方法,體現了多型性。老闆娘兼專案經理要求阿珠和阿花兩個程式設計師...

物件導向程式設計

第1頁共2頁 9 編寫乙個控制台程式,要求 編寫乙個函式get scores 接受使用者輸入的語文 數學 物理 化學和英語5科成績,在main 中利用get scores 接受輸入,然後計算總成績與平均成績,main 與get scores 之間不得使用全域性變數通訊。10 編寫乙個控制台程式,使用...

物件導向程式設計複習

1.宣告乙個複數類complex,過載運算子 使之能用於複數的加 減,運算子過載函式作為complex類的成員函式。請程式設計序實現。2.分別宣告teacher 教師 類和cadre 幹部 類,採用多重繼承方式由這兩個類派生出新類teacher cadre 教師兼幹部 要求 1 在兩個基類中都包含姓...