面向介面設計和編程——(面向對象、面向介面、面向過程、面向實現) --轉載

来源:http://www.cnblogs.com/Realwate/archive/2016/02/20/5202546.html
-Advertisement-
Play Games

引言--面向介面所處的設計模式中的位置。 其實,我認為Java/C#比C++高級的其中一個原因是,它對面向介面編程的支持。不要誤解,並不是說C++不支持面向介面編程,而是說C++的語法中沒有這種天然的機制。 面向對象之於面向過程,面向介面之於面向實現。但基本上,面向介面和麵向實現都基於面向對象的模式


引言--面向介面所處的設計模式中的位置。

其實,我認為Java/C#比C++高級的其中一個原因是,它對面向介面編程的支持。不要誤解,並不是說C++不支持面向介面編程,而是說C++的語法中沒有這種天然的機制。

面向對象之於面向過程,面向介面之於面向實現。但基本上,面向介面和麵向實現都基於面向對象的模式,也就是說面向介面並不能稱為比面向對象的更高的一種編程模式。而是在面向對象中大的背景下的一種更加合理的軟體設計模式,它增強了類與類之間,模塊與模塊的之間的低耦合性,是軟體系統更容易維護、擴展。

不管是面向什麼,都是一種軟體設計模式,與具體的語言有沒多大關係。

就像之前介紹C語言一樣,並不是說C語言這種面向過程的語言不能做面向對象編程,而是說,C語言當初設計的並沒有針對面向對象軟體系統的風格而進行設計的。由於後來的面向對象軟體設計風格的流行,後來者語言C++/java/C#都在語言設計上充分考慮了支持面向對象的方便性,所以這些語言稱為面向對象編程語言。

根據語言之間沒有能力大小的理論,C是可以進行面向對象編程的(實踐上也是可行的)。

上面理論同樣適合討論—— C++之於面向介面編程。

面向介面軟體設計,並不是在java或C#中出現interface這種關鍵字後才有的。還是那句話,它是一種軟體設計模式,與具體語言無關,C++或者C都可以並且也大量使用過這種編程模式。而僅是因為這種模式的優點,java與C#才在C++的基礎上,設計成更好的支持面向介面編程(裡面提出的語言級別的介面的概念)。

兩種interface的概念

這就需要瞭解語言(java/C#)級上的interface,與軟體設計級別上的interface了。可以說,是現有軟體設計上的interface概念,然後那些“後起”語言,就為了充分的支持這種軟體設計(畢竟設計最終要用語言實現),而加入了"interface"這個關鍵字及其相關概念。也就是說,即使java/C#不使用它們語言自帶的interface技術,也可以進行面向介面編程(你或許知道——使用抽象類)。這麼講吧,兩種介面不屬於同一級別的東西,並不應該拿來比較,但一定要比較,可以認為,軟體設計上的介面概念比語言級別的介面概念要大。

面向介面(設計)編程是什麼意思,為了什麼,有什麼好處

(1)說文解字

“面向”這個詞,在軟體設計編程中得到大量的使用。但似乎我們有不是很明白它到底代表什麼意思。就像前面糾結“面向對象”這個詞是什麼意思的時候,我們也需要對“面向介面”這個詞有較為深刻的解析。

“對象”與“數據”的區別在於“對象是信息與處理信息的方法的載體,而數據只是信息的載體”,而“面向”這個詞的關鍵含義是,當我們在設計一個系統、實現一個系統的時候,我們基於、以什麼為設計和編程的目標。面向過程設計和編程,設計師和程式員在設計和編程的時候所面對的、和所能夠利用的東西往往只是一些變數。而面向對象則不同,他們面對的是一些對象,可以說是一些活生生的對象。

比如你要編程式控制制一個人。

面向過程編程中,給你的只是一個人的信息體(結構體),這個信息體中包含完整描述一個人的各種“靜態信息”的數據,例如姓名、性別、年齡、體重、樣貌等等,這種時候,如果要控制一個人,讓他說一句話“你好嗎”。那麼你就需要,專門設計一個函數或者一個過程,來調用這個人的所具備的各種機體,然後讓他說出話來(實際上是等於知道一個人如果把那句話發出來)。這是一個很讓人頭痛的東西,而我們希望的是程式員或這是設計人員面向的是一個活生生的人,這個人是會說話的,它並不需要我們叫他如何和說話,我們要讓它說話只需要將說的內容傳遞給他,而他就會說出來。這個說話就是這個人的“動態信息”。

面向對象,就是提供給程式員一個完整的包括靜態信息和動態信息的對象。讓程式員不必花時間在該個體的某些動作的實現過程上。就像一個動物飼養員一樣,不同的動物他們自己吃飯有不同的吃飯,動物飼養員只需要給予不同的動物不同的食物就可以了,前提是這個動物是有自主吃這個動作的。這就是面向對象最基本的概念——提供給設計師或程式員的是一個對象,一個包含那個個體的靜態(數據)與動態(處理數據的方法)信息的整體。

有了上面的概念,我們可以首先確定“面向”是什麼一會事,實際上就是他的字面意義,就是在設計者或程式員進行工作的時候,他們做面對的是一個什麼?

(2)解釋開始

面向實現,就是在面向對象編程的時候,當我們要控制某個類的對象,那麼我們會直接在當前程式中(自身類)中,實例化該類,然後通過該類調用相應的方法。這是一種最基本的面向對象編程模式。

有人說,這有問題嗎?這不就是我們所慣用的面向對象設計方法嗎?要使用某個對象,就像實例化它然後調用它的方法,這種模式還做了比較好的低耦合性。你調用的對象,如果實現發生了變化,你基本不需要出現什麼修

改。但就一個問題,就很難解決。

(3)難以解決的問題

動物飼養員喂養三種動物(雞、鴨、鵝),只需要使用上述面向實現的方法,分別實例化那些動物,然後分別調用那些動物的“吃”這個方法。對那些動物如何次這些東西,是他們自己的是,飼養員根本不需要管,所以飼養員的程式基本穩定,這也就是面向對象的優點。(各種動物的個數不是問題,關鍵就是飼養員掌握了三種動物的類,實例化他們、調用他們只是一個迭代過程而已)。

但是,如果這時,動物園的新安排一種動物(狗),給這個飼養員飼養,狗這個動物的類已經做好,無需飼養員管,反正這種動物一定是用嘴吃食物就是(飼養員才可能知道怎麼飼養)。但是,這個時候,需要對飼養員這個對象的類進行修改,加入實例化狗和調用狗吃食物的方法。

這就出現了問題,我們最理想的狀態就是,動物園改點東西(加入那些狗),然後給飼養員就是了,這個時候因為加入一些狗,需要對飼養員從新培訓(更新他的代碼),這是我們不想要的。這也說明這種模式設計方法並沒有做到很好的低耦合性。這也是普通的面向對象設計和編程手段做不到的。

(4)分析問題

解決上述問題的方法,需要我們從新思考面向問題。前面我們說的面向實現這個概念可以暫且不管,在上述的設計編程的思想下,飼養員,直接面向的是,它要飼養的那些動物(並且區別對待不同的動物)。而實際上,飼養員基本不需要區別對待。因為各種動物吃飯的細節(實現)根本不是你要管的。那麼在這種情況下,作為普通實驗員的你,為什麼要區別對待不同的動物呢?

也就是說,我們所要的更好的狀況是,飼養員只要知道他們是動物,有吃的動作就可以了。如果飼養員是按照那種模式培訓的,那麼動物園隨便怎麼安排新的物種,或者下掉新的物種,飼養員那邊的代碼就完全不動了,這就做到了低耦合了。

(5)初次解決(設計)

那麼如何實現上面的目標呢?

我們知道,飼養員之前面向的是不同種類的動物,而現在我們只需要讓他面向動物。什麼意思?更抽象一層了。於是我們需要怎麼實現,那就是繼承嘛!也就是說,我們需要在設計每個動物的時候需要讓他們繼承“動物”這個更為上層的一個類。並且還要使用多態的技術才行。

也就是說,根據多態的觀點,如果飼養員得到的是動物園給它的一批動物的指針(基類指針),指針指向的可能有多種動物(派生類指針),飼養員可以通過這個指針調用那些動物的吃的動作就可以了。這也就是要求,每個動物必須遵守從基類繼承並覆蓋一個虛函數,這樣,飼養員,通過動物指針調用的吃函數,才會動態綁定到各個動物上去。而這個飼養員是完全不必知道的。而動物園對飼養員進行編程(管理)的時候傳給飼養員的東西只是那些動物的指針而已。所以只要後來加上的動物,是通過是以動物為基類,飼養員就完全不必更新什麼!

你覺得這是什麼編程,或則說你覺得,這個飼養員面向的是什麼?對象嗎?對,依然是,但是是屬於更為抽象的一個對象(動物),而因為它面向得更為抽像,導致,外界的更新基本不需要改他的改變。

(這也可以與我們學習有些類似,如果你學的是一些過於具體的東西,當新的類似的東西出現,你又要學那個東西,如果你學的是較為抽象的基本、一般原理,當新的類似的東西出現,你套用就是,這就是“一通萬通”,關鍵是第一個通是通在一般原理,後面的通是通在各種類似具體知識)

我們為什麼不叫“面向基類編程”呢?因為上面介紹的這種模式,似乎,就是面向更為抽象的基類編程嘛。對的,這種說法很正確,並且也說出了這種編程模式的基本思想。但是,當我們需要解決另外一個問題的時候,這種說法,不具備廣泛的適應性。

(6)進一步的問題:

還是前面動物園為背景。現在加入檢疫員這個角色(類)。這個類對象需要對動物園的動物進行檢疫,不同的動物有不同的檢疫方法,但是這個具體的動作內容,包含在各個動物內部,也就是說,你可以想象成,檢疫的時候,拿起一隻動物,檢疫員是按照這個動物信息提上所攜帶的相關檢疫信息,進行檢疫。所以,這個檢疫員與飼養員沒有太多大區別,關鍵是,飼養員調用“吃”這個操作,而檢疫員調用“檢疫”這個動作。

按照前面的編程模式,“動物”內中應該至少包括“吃”和“檢疫”兩個函數,(雖然這兩個函數可能都沒有實際內容,但他們的功能是很多的)。於是檢疫員同樣做到了與飼養員那樣的在系統中的低耦合性。

但是,你會發現,飼養員面向的是“動物”,檢疫員面向的也是“動物”,而是不是有些問題呢?實際上,檢疫員和飼養員所關註的動物的方面是不同的(雖然他們都不在乎是什麼動物),飼養員只在乎動物“吃”這個方面,而檢疫員只在乎動物“檢疫”這個方面。

(7)進一步分析問題

有人會問,這個有問題嗎?理論上講,只要動物園嚴加管理,對飼養員進行嚴加培訓,是沒有多大問題的,但怕就怕在,飼養員給動物檢疫,檢疫員給動物東西吃。為什麼會這樣?為什麼你把整個“動物”都暴漏個了兩者,也就是說,你並沒有區別對待這兩種角色。還有一個不好的問題是,給檢疫員編程的時候,如果動物這個類太複雜了(包含太多的方法和屬性),會是編程趨於困難,如果,給檢疫員的只是一個它所能關註和需要調用使用的動物的一部分,那麼編程就方便了。並且也不會讓檢疫員調用到“吃”這個方法,這是一種“隔離”,也是一種安全措施。

也許到現在有些人有點模糊了。前面認為面向對象(具體對象)編程不好,認為面向基類(抽象)編程可以降低耦合,現在好像又需要具體了。其實兩者一定不矛盾。前者將各個具體動物歸為“動物”,後則將“動物”分解成不同的方面。兩者一點都不矛盾。

(8)解決問題

那麼如何解決這個問題呢?

(9)基類和介面(引深)

這就讓我們想到了,現代編程中的兩個概念。基類和介面。他們的共同特點就是讓派生類繼承或實現(暫時可以理解成一個意思)。從語法結構上看,基類和介面的結構非常相似,那麼他們到底有什麼區別呢?基類只能單繼承,而介面可以進行多實現。這種規定又是為什麼?

這就是我們要理解的自然界中的事物,通常只屬於某一個類。也就是說雞就是動物類,不應該屬於其他類。

這種做法和不合理。要知道在這種做法的背景下,類只能繼承一個類哦。

我們再看看,不同類的東西,也有相同的屬性,是否我們能夠更具這些屬性來分類呢?

人和動物不是一個類(雖然也是),但是人和動物都有“吃”和“睡”這樣的屬性,那麼是不是人和動物都可以歸類為可以“吃”的,可以“睡”呢?對的!可以這麼分的,但是,它與通常的分發是有本質不同的。表達除了一種"I'm is..." 和"I have ..."之間的區別。為了區分兩種,在軟體設計行業中就出現了類與介面的不同概念,並且在“後起的”程式設計語言java和C#中,也對著兩者做的顯示的區分(從語法上進行定義)。

我們再來看看動物園裡的那些動物。他們應該都屬於一個類“動物”但是他們還有許多東西是共有的,並且這些東西不是他們特有的,人也可以有,例如“吃”,“睡”,“檢疫”(雖然通常不這麼說)等。更正確的設計方法,並應該讓“吃”,“睡”這些東西獨屬於“動物”,而對於人,又從新定義類似的概念。這樣並不符合自然規律和特點。而應該是,對於這些“吃”,“睡”什麼的,應該獨立定義,然後,動物可以繼承它,人也可以繼承它,但是動物和人不屬同類(不要糾結啊,雖然他們也是同類)。這樣你發現,自然間的各種事物,不在是我們之前的樹形結構的聯繫,而是更具不同的方面某個東西有多方面的從屬聯繫。這樣我們描述自然的能力就更為豐富了。而java/C#與C++的區別在於,他們嚴格區別開了前面我們介紹的基類和介面的區別。、

抽象類和介面的比較

所以雖然通常,我們老是將“介面”和“抽象類”進行比較,但是,事實上他們不屬於同一個級別的東西,可以這麼說吧,我們有了類的概念,但是我們將類分成了“唯一類”和“介面”(在後進語言中才有區別),然後,當初,C++只有類的概念,但是這個類概念包含了後來在java中的類和介面的概念。抽象類(具有純虛函數的類)存在的最初意義,是不希望你實例化這樣的一個不能代表任何東西的類。實際上在C++面向介面、面向對象編程的過程中,是可以不使用到抽象類的概念的。介面由於完全從類分離出來的一種特殊類,它負責對繼承它的類的方法進行規範,正是因為介面的這個特殊作用,使得,它不會語義上不需要對方法的實現,這一點,在java和C#中,被釘死了。而在C++中,沒有這種規定,但建議這麼做。

(10) 再回到我們的動物園——全面解決問題

我們定義的時候,首先應該定義“吃”這個類(C++語法意義上的類,其實是涉及意義上的介面,裡面的吃,是定義為純虛函數,還是普通虛函數都無所謂,但是必須是虛函數,這也是java的優勢,否則不能出現多態特性,那前面講的也白搭了)。也需要相應的定義“檢疫”這個類。我們現在就改口說他是介面(在C++中,只能說他的設計意義上的介面)。

然後,定義“動物”這個類,裡面包含了“動物”的特質信息,同時要繼承“吃”和“檢疫”兩個介面。這樣一個完整的動物定義(相對完整)就出現了。

我們知道,雞、鴨、鵝、狗,是要繼承“動物”這個類的。

現在給飼養員進行編程:

我們還用“動物”作為他面向的東西嗎?自然不會,我們用“吃”做為他面向的東西,因為不管是C++,還是C#/java.他們都保證了介面和基類在這方面的特性,所以,使用“吃”作為面向的東西來實現我們要實現的多態性是語法可行的。

同樣,給檢疫員編程的時候,使用“檢疫”作為面向的東西。

這樣做,就既可以保證了,飼養員和檢疫員和系統的低耦合性,同時也保證了他們各自職能幹他們該乾的事情。可以說幾乎完美了。

總結

現在我們在來看看,我們用了什麼設計模式。對,面向介面,實驗員和檢疫員編程的時候,就是面向介面。所以面向介面編程就是這麼來的啦。而面向實現基本上是因為提出了面向介面之後,才出現的這個與它相對的編程方法。沒有多大意義。

從我們所說的動物園的例子中看,似乎面向介面比面向對象更抽像了一級,但是,這隻是在面向對象這個天才的實際模式之下的一點優化而已。所以,不能說面向介面是比面向對象更高級的設計模式。

面向介面的核心意義就是,編程的時候,不是直接面向你要控制的那個對象(普通面向對象),而是通過利用繼承與多態的功能,面向一個更抽象的東西。這樣降低的模塊之間的耦合度,提高了代碼復用。通過近一步分析提取了“介面”這個管理意義上的概念,並且在此基礎上,進一步減低了模塊的耦合度,提高了模塊的單一性。這就是面向介面編程。(其實,想要瞭解它的核心,可以稱它為面向基類編程)。

我們發現,“動物”這個類的吃的動作,是不應該有什麼內容的,因為動物是一個抽象的東西,不想雞、鴨什麼的,他們吃的動作可以具體。所以,動物類中吃的動作必須有,否則:從管理上,你無法統一所有具體動物吃的外界介面;從編程上你也無法讓編譯器通過飼養員的程式,因為無法通過“動物”指針引用吃這個動作。

所以“吃”這個動作,在“動物”類中,頂多有一些通用的內容。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 近段時間,需要寫一個小功能,就是需要判斷程式是否已經運行。某個程式安裝後,也許被多個用戶運行。那怎樣判斷當前用戶已經運行了此程式了呢?下麵是Insus.NET的做法,就是:《VB.NET WinForm獲取運行程式用戶名》http://www.cnblogs.com/insus/p/5194839.
  • (轉)這裡給大家分享幾個VS版本,都是最終版的,也是中文版的!. Visual Studio 2005:http://pan.baidu.com/s/1c0eudyS Visual Studio 2008:http://pan.baidu.com/s/1i3GJ7pj Visual Studio 2
  • 以下非原創作品,但都是自己看過理解並寫過,記錄下來,以便之後項目的使用或其它用途。 (1)只需要簡單配置單一屬性值: 1 <configuration> 2 <configSections> 3 <!--配置讀取的全名稱--> 4 <section name="simple" type="Confi
  • 使用 HttpResponse 對象 HttpResponse 對象是與 HttpRequest 對象相對應的,用來表示構建中的響應。它當中提供了方法和屬性可供我們自定義響應,有一些在使用 MVC 視圖的時候很少使用到,但是在使用其他組件的時候可能十分有用,比如模塊是處理器。 同 HttpReque
  • HTTP請求工具類,適用於微信伺服器請求,可以自測 代碼; 1 /// <summary> 2 /// HTTP請求工具類 3 /// </summary> 4 public class HttpRequestUtil 5 { 6 #region 請求Url 7 8 #region 請求Url,不發
  • 在工作中我們經常會遇到格式轉換的問題,有的時候是將JSON轉換成DataTable、DataSet或是List等,也有可能將DataTable、DataSet或是List轉換成JSON的,抽了點時間把這些方法整合了一下,希望對大家有所幫助,如果有什麼問題請指出來,共同探討。 代碼: 1 using
  • 使用 HttpRequest 對象 HttpRequest 對象描述的是一個正在被處理的 HTTP 請求。下表列舉了 HttpRequest 中的屬性,它們提供了當前請求的相關信息(HttpRequest 類定義了一些方法和屬性,我們會逐步講解當中的一些屬性)。 表 1 – HttpRequest
  • https://msdn.microsoft.com/zh-cn/library/system.text.regularexpressions.regex(v=vs.110).aspx /// <summary> /// /// </summary> /// <param name="sender"
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...