1. 程式人生 > >那些年搞不懂的高深術語——依賴倒置•控制反轉•依賴注入•面向介面程式設計

那些年搞不懂的高深術語——依賴倒置•控制反轉•依賴注入•面向介面程式設計

那些年,空氣中彷彿還能聞到漢唐盛世的餘韻,因此你決不允許自己的臉上有油光,時刻保持活力。然而,你一定曾為這些“高深術語”感到過困擾——依賴倒置•控制反轉•依賴注入•面向介面程式設計。也許時至今日,你仍對它們一知半解。不過就在今天,這一切都將徹底改變!我將帶領你以一種全新的高清視角進入奇妙的程式設計世界,領略涵泳在這些“高深術語”中的活潑潑的地氣,以及翩躚於青萍之末的雲水禪心。

·內聚 

      內聚,通俗的來講,就是自己的東西自己保管,自己的事情自己做。

    經典理論告訴我們,程式的兩大要素:一個是資料(data),一個是操作(opration)。而 PASCAL之父Nicklaus

 Wirth則進一步提出了“程式 = 資料結構 + 演算法”的著名公式。雖然提法上有所差異,但是其根本內涵卻是一致的,微妙的差別在於,“資料 + 操作”是微觀的視域,“資料結構 + 演算法”則是中觀的視域。而在巨集觀的視域下,我認為“程式 = 物件 + 訊息”。物件是什麼?物件就是保管好自己的東西,做好自己的事情的程式模組——這就是內聚!傳統的面向過程程式設計方法由於割裂了資料結構和演算法,使得軟體的內聚性普遍低迷,曾一度引發了軟體危機。試想,大家都自己的東西不好好保管,自己的事情也不好好做,不引發危機才怪呢!當然,物件的內聚只是內聚的一個層次,在不同的尺度下其實都有內聚的要求,比如方法也要講內聚,架構也要講內聚。

   《周易·彖傳》中講“乾道變化,各正性命,保合太和,乃利貞”,就是要求每一個個體因循著各自的稟賦而努力成就各自的品性,然後各自保全,彼此和合,最終達成宇宙的完滿狀態。《論語·憲問》中,子路問君子。子曰:“修己以敬。”曰:“如斯而已乎?”曰:“修己以安人”,更是明確的教導我們要不斷提高自身的內聚性,最大限度地減少給他人造成的麻煩,從而達到安人、安百姓、安天下的目標。我想,成長的過程就是一個不斷提升內聚的過程。“自己的東西自己保管,自己的事情自己做”,這些孩提時代的教誨,放到今天仍能讓不少“大人”臉紅不已。太多的人保管不好自己的“東西”,保管不好自己的身體,保管不好自己的婚姻,更保管不好自己如蛛絲般震顫飄蕩的狂亂的心。至於做好自己的事情,則更是惘然,甚至很多人連自己的事情是什麼都搞不清楚,因此渾渾噩噩,飽食終日。內聚,是一個值得我們好好反思的問題。

 

·依賴·耦合

       在面向物件程式設計中,物件自身是內聚的,是保管好自己的資料,完成好自己的操作的,而對外界呈現出自己的狀態和行為。但是,沒有絕對的自力更生,對外開放也是必要的!一個物件,往往需要跟其他物件打交道,既包括獲知其他物件的狀態,也包括仰賴其他物件的行為,而一旦這樣的事情發生時,我們便稱該物件依賴於另一物件。只要兩個物件之間存在一方依賴一方的關係,那麼我們就稱這兩個物件之間存在耦合。 比如媽媽和baby,媽媽要隨時關注baby的睡、醒、困、哭、尿等等狀態,baby則要仰賴媽媽的餵奶、哄睡、換紙尿褲等行為,從程式的意義上說,二者互相依賴,因此也存在耦合。首先要說,耦合是必要的。我們來看以下這個實驗。

【王陽明與山中之花

 View Code

      由於王陽明這個物件不依賴山花這個物件,又沒有其他的方式來獲知山花的盛開狀態,所以他要麼選擇不說,要麼瞎說,但不說編譯是通不過,而瞎說作為王陽明來講也是通不過的,所以這個系統是無法成立的。要想系統成立,必須要這樣寫:

        public bool AdmireFlowers()
        {
            return flower.IsBloomed; ; 
        }

     無論這個山花物件是怎麼來的,作為引數傳入還是作為屬性設定、還是在內部構造出來,總之,王陽明與山花之間發生了依賴,二者之間產生了耦合。 當然,這是一個很淺顯的問題。有趣的是王陽明對此事的看法:“你未看花時,花與你同寂;你來看花,花於你則一時分明起來。可見心外無物!”王陽明講的是對的!“心外無物”翻譯技術語言是這樣的:不存在耦合的兩個物件必然拿不到對方的引用! 

·耦合度·解耦和

      耦合的程度就是耦合度,也就是雙方依賴的程度。上文所說的媽媽和baby就是強耦合。而你跟快遞小哥之間則是弱耦合。一般來說耦合度過高並不是一件好事。就拿作為IT精英的你來說吧,上級隨時敦促你的工作進度,新手頻繁地需要你指導問題,隔三差五還需要參加酒局飯局,然後還要天天看領導的臉色、關注老婆的心情,然後你還要關注程式碼中的bug 、bugbug,和需求的變化、變化、變化,都夠焦頭爛額了,還猝不及防的要關注眼睛、頸椎、前列腺和頭髮的狀態,然後你再炒個股,這些加起來大概就是個強耦合了。從某種意義上來說,耦合天生就與自由為敵,無論是其他物件依賴於你,還是你依賴其他物件。比如有人嗜煙、酗酒,你有多依賴它們就有多不自由;比如有人家裡生了七八個娃,還有年邁的父母、岳父母,他們有多依賴你,你就有多不自由。所以老子這樣講:“五音令人耳聾,五色令人目盲,馳騁狩獵令人心發狂,難得之貨令人行妨。”盧梭也是不無悲涼的說“人生而自由,卻又無往而不在枷鎖中”。因此,要想自由,就必須要降低耦合,而這個過程就叫做解耦和。

·依賴倒置(Dependence Inversion Principle)

    解耦和最重要的原則就是依賴倒置原則:

    高層模組不應該依賴底層模組,他們都應該依賴抽象。抽象不應該依賴於細節,細節應該依賴於抽象。 

   《資本論》中都曾闡釋依賴倒轉原則——在商品經濟的萌芽時期,出現了物物交換。假設你要買一個IPhone,賣IPhone的老闆讓你拿一頭豬跟他換,可是你並沒有養豬,你只會程式設計。所以你找到一位養豬戶,說給他做一個養豬的APP來換他一頭豬,他說換豬可以,但是得用一條金項鍊來換——所以這裡就出現了一連串的物件依賴,從而造成了嚴重的耦合災難。解決這個問題的最好的辦法就是,買賣雙發都依賴於抽象——也就是貨幣——來進行交換,這樣一來耦合度就大為降低了。

再舉一個程式設計中的依賴倒置的例子。我們知道,在通訊中,訊息的收發和訊息的處理往往密不可分。就一般的通訊框架而言,訊息的收發通常是已經實現了的,而訊息的處理則是需要使用者來自定義完成的。先看一個正向依賴的例子:。tcpServerEngine是StriveEngine.dll提供通訊引擎,它釋出有一個MessageReceived事件。假設我定義了一個CustomizeHandler類來用於訊息處理,那麼CustomizeHandler的內部需要預定tcpServerEngine的MessageReceived事件,因此customizeHandler依賴於tcpServerEngine,這就是一個普通的依賴關係,也就是高層模組依賴於低層模組。

                

     而則應用了依賴倒轉原則。ESFramework定義了一個IcustomizeHandler介面,使用者在進行訊息處理時,實現該介面,然後將其注入到rapidPassiveEngine客戶端通訊引擎之中。 

 View Code

     很明顯,相比於上一個例子,這裡的依賴關係變成了rapidPassiveEngine依賴於customizeHandler,也就是說依賴關係倒置了過來,上層模組不再依賴於底層模組,而是它們共同依賴於抽象。rapidPassiveEngine依賴的是IcustomizeHandler介面型別的引數,customizeHandler同樣是以實現的介面的方式依賴於IcustomizeHandler——這就是一個依賴倒置的典範。

·控制反轉(Inversion of Control)

      控制反轉跟依賴倒置是如出一轍的兩個概念,當存在依賴倒置的時候往往也存在著控制反轉。但是控制反轉也有自己的獨特內涵。

      首先我們要區分兩個角色,server 跟 Client,也就是服務方和客戶方。提供服務端的一方稱為服務方,請求服務的一方稱為客戶方。我們最熟悉的例子就是分散式應用的C/S架構,服務端和客戶端。其實除此之外,C/S關係處處可見。比如在TCP/IP協議棧中,我們知道,每層協議為上一層提供服務,那麼這裡就是一個C/S關係。當我們使用開發框架時,開發框架就是作為服務方,而我們自己編寫的業務應用就是客戶方。當Client呼叫server時,這個叫做一般的控制;而當server呼叫Client時,就是我們所說的控制反轉,同時我們也將這個呼叫稱為“回撥”。控制反轉跟依賴倒置都是一種程式設計思想,依賴倒置著眼於呼叫的形式,而控制反轉則著眼於程式流程的控制權。一般來說,程式的控制權屬於Client,而一旦控制權交到server,就叫控制反轉。比如你去下館子,你是Client餐館是server。你點菜,餐館負責做菜,程式流程的控制權屬於Client;而如果你去自助餐廳,程式流程的控制權就轉到server了,也就是控制反轉。

      控制反轉的思想體現在諸多領域。比如事件的釋出/ 訂閱就是一種控制反轉,GOF設計模式中也多處體現了控制反轉,比如典型的模板方法模式等。而開發框架則是控制反轉思想應用的集中體現。比如之前所舉的ESFramework通訊框架的例子,通訊引擎回撥使用者自定義的訊息處理器,這就是一個控制反轉。以及ESFramework回撥使用者自定義的群組關係和好友關係,回撥使用者自定義的使用者管理器以管理線上使用者相關狀態,回撥使用者自定義的登陸驗證處理,等等不一而足。再比如與ESFramework一脈相承的輕量級通訊引擎StriveEngine,通過回撥使用者自定義的通訊協議來實現更加靈活的通訊。

        

      由此我們也可以總結出開發框架與類庫的區別:使用開發框架時,框架掌握程式流程的控制權,而使用類庫時,則是應用程式掌握程式流程的控制權。或者說,使用框架時,程式的主迴圈位於框架中,而使用類庫時,程式的主迴圈位於應用程式之中。框架會回撥應用程式,而類庫則不會回撥應用程式。ESFramework和StriveEngine中最主要的物件都以engine來命名,我們也可以看出框架對於程式主迴圈的控制——它會為你把握方向、眼看前方、輕鬆駕馭! 

·依賴注入(Dependency Injection)

  依賴注入與依賴倒置、控制反轉的關係仍舊是一本萬殊。依賴注入,就其廣義而言,即是通過“注入”的方式,來獲得依賴。我們知道,A物件依賴於B物件,等價於A物件內部存在對B物件的“呼叫”,而前提是A物件內部拿到了B物件的引用。B物件的引用的來源無非有以下幾種:A物件內部建立(無論是作為欄位還是作為臨時變數)、構造器注入、屬性注入、方法注入。後面三種方式統稱為“依賴注入”,而第一種方式我也生造了一個名詞,稱為“依賴內生”,二者根本的差異即在於,我所依賴的物件的建立工作是否由我自己來完成。當然,這個是廣義的依賴注入的概念,而我們一般不會這樣來使用。我們通常使用的,是依賴注入的狹義的概念。不過,直接陳述其定義可能會過於詰屈聱牙,我們還是從具體的例子來看。

      

  比如,它實現了多媒體裝置(麥克風、攝像頭、桌面、電子白板)的採集、編碼、網路傳送、解碼、播放(或顯示)等相關的一整套流程,可以快速地開發出視訊聊天系統、視訊會議系統、遠端醫療系統、遠端教育系統、網路監控系統等等基於網路多媒體的應用系統。然而,OMCS直接支援的是通用的語音視訊裝置,而在某些系統中,需要使用網路攝像頭或者特殊的視訊採集卡作為視訊源,或者其它的聲音採集裝置作為音訊源,OMCS則提供了擴充套件介面——使用者自己實現這個擴充套件的介面,然後以“依賴注入”的方式將物件例項注入到OMCS中,從而完成對音、視訊裝置的擴充套件。擴充套件方法詳情參考

      “依賴注入”常常用於擴充套件,尤其是在開發框架的設計中。從某種意義上來說,任何開發框架,天生都是不完整的應用程式。因此,一個優秀的開發框架,不僅要讓開發者能夠重用這些久經考驗的的卓越的解決方案,也要讓開發者能夠向框架中插入自定義的業務邏輯,從而靈活自由地適應特定的業務場景的需要——也就是說要具備良好的可擴充套件性。比如上面提到的OMCS網路語音視訊框架可應用於音、視訊聊天系統、視訊會議系統、遠端醫療系統、遠端教育系統、網路監控系統等等基於網路多媒體的應用系統;以及能夠應用於即時通訊系統,大型多人線上遊戲、線上網頁遊戲、檔案傳送系統、資料採集系統、分散式OA系統等任何需要分散式通訊的軟體系統中——這種良好的擴充套件性都與“依賴注入”的使用密不可分!

·面向介面程式設計

      談到最後,“面向介面程式設計”已經是呼之欲出。無論是依賴倒置、控制反轉、還是依賴注入,都已經蘊含著“面向介面程式設計”的思想。面向介面,就意味著面向抽象。作為哲學範疇而言,規定性少稱為抽象,規定性多稱為具體。而介面,就是程式中的一種典型的“抽象”的形式。面向抽象,就意味著面向事物的本質規定性,擺脫感性雜多的牽絆,從而把握住“必然”——而這本身就意味著自由,因為自由就是對必然的認識。

      也許以上的這段論述太過“哲學”,但是“一本之理”與“萬殊之理”本身就“體用不二”——總結來看,依賴倒置、控制反轉、依賴注入都圍繞著“解耦和”的問題,而同時自始至終又都是“面向介面程式設計”的方法——因此,“面向介面程式設計”天生就是“解耦和”的好辦法。由此也印證了從“抽象”到“自由”的這一段範疇的辯證衍化。

      “面向物件”與“面向介面”並非兩種不同的方法學,“面向介面”其實是“面向物件”的內在要求,是其一部分內涵的集中表述。我們對於理想軟體的期待常被概括為“高內聚,低耦合”,這也是整個現代軟體開發方法學所追求的目標。面向物件方法學作為現代軟體開發方法學的代表,本身就蘊含著“高內聚,低耦合”的思想精髓,從這個意義上來說,“面向物件”這個表述更加側重於“高內聚”,“面向介面”的表述則更加側重於“低耦合”——不過是同一事物的不同側面罷了。

      除此之外,我們也能從“面向介面程式設計”的思想中得到“世俗”的啟迪——《論語》裡面講,不患無位,患所以立;不患人之不己知,患其不能也——就是教導我們要面向“我有沒有的本事?”、“我有沒有能力?”這樣的介面,而不是面向“我有沒有搞到位子?”、“別人了不瞭解我?”這樣的具體。依我看,這是莫大的教誨!

相關推薦

那些高深術語——依賴倒置控制反轉依賴注入面向介面程式設計

那些年,空氣中彷彿還能聞到漢唐盛世的餘韻,因此你決不允許自己的臉上有油光,時刻保持活力。然而,你一定曾為這些“高深術語”感到過困擾——依賴倒置•控制反轉•依賴注入•面向介面程式設計。也許時至今日,你仍對它們一知半解。不過就在今天,這一切都將徹底改變!我將帶領你以一種全新的

C#掃盲篇(二)依賴倒置控制反轉依賴注入面向介面程式設計--滿腹經綸的說

 掃盲系列的文章收到了廣大粉絲朋友的支援,十分感謝,你們的支援就是我最大動力。 我的掃盲系列還會繼續輸出,本人也是一線碼農,有什麼問題大家可以一起討論。也可以私信或者留言您想要了解的知識點,我們一起進步,共同向著高階進發。 掃盲系列文章都是圍繞著下圖知識點來做的,後續還會出一些從基礎到進階系列的Co

TF-的TF矩陣加法

其中 oat int 矩陣 ssi p12 谷歌 conv2 eval 看谷歌的demo mnist,卷積後加偏執量的代碼 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool_

的github

介紹 老師 git .com 自己 簡單的 都得 hub post 我也是在網上看了不少的教程,但還是一臉懵逼。首先還是先寫出自己的github的地址吧。我的github地址為:https://github.com/UchinoMENG.這個網址裏面還是有一些東西的,但都是

據說,80%的人都雜湊演算法 區塊鏈 雜湊演算法

本文約9000字+,閱讀(觀看)需要52分鐘 聊到區塊鏈的時候也少不了會聽到“雜湊”、“雜湊函式”、“雜湊演算法”,是不是聽得一頭霧水?別急,這一講我們來講講什麼是雜湊演算法。 雜湊是一種加密演算法 雜湊函式(Hash Function),也稱為雜湊函式或雜湊函式。雜湊函式是一個

Python 正則表示式,實戰篇! 再? 算我輸~

整理自: Automate the Boring Stuff with Python 作者: Al Sweigart 1. 建立正則表示式物件和匹配Regex物件 向 re.compile() 傳入一個字串值,表示正則表示式,它將返回一個 Regex

未來五人工智慧的程式設計師會被淘汰嗎?

前提摘要: 從PC到網際網路、移動網際網路、雲端計算、大資料,再到現在的人工智慧、區塊鏈,半個多世紀以來,人類科技正以前所未有的速度飛速迭代。緊跟潮流、看對方向的幸運者大多數都成為新時代的弄潮兒,而默守陳規者則在時代的濤聲中逐漸湮滅。有人說下一個五年將是人工智慧的時代,不懂人工智慧的程式設計

昨天,游標能夠跟隨了,不過系統呼叫能正常工作,還沒找到原因,暫時也,就這樣吧

/************************************************************************/ /* Macros Declaration

C/C++指標還是陣列?用sizeof解釋struct大小!

陣列?指標?聽說c++打算廢棄指標了,誰讓指標這麼難呢!我的環境:>uname -a CYGWIN_NT-10.0-WOW DESKTOP-499IG24 2.10.0(0.325/5/3) 2018-02-02 15:21 i686 Cygwin可見為32bit核心,

想學習大數據卻Hadoop?阿裏雲工程師帶你三步解讀Hadoop!

大數 網易 挖掘 支持 文件存儲 規模 淘寶 階段 設計 一、什麽是Hadoop? Google發表了兩篇論文:描述如何以分布式方式存儲海量數據的Google文件系統和描述如何處理大規模分布式數據的MapReduce:大型集群上的簡化數據處理。受這兩篇論文的啟發,DougC

【當你以備課的心態去學習,沒有你的內容】首篇

    今天是悶熱的一天 太陽見不到 但是空氣乾燥而且讓人喘不過來氣。     8:00到圖書館 剛剛踏進有絲絲的清涼 但是隨著電梯的升高 氣溫也升了起來 是我太久沒有來過的原因麼?為何圖書館沒有了空調。     上午看了作業系統和離散數學的網易視訊,收益匪淺,但是ege圖

未來五人工智慧的程式設計師會被淘汰

1. 話題背景 最近人工智慧很火,區塊鏈很火。都吹的上天的,工資非常高。空口無憑,來看看相關的資料。 薪資高,人才缺口大。 2、程式設計師的分類 程式設計師有很多工種,前端,後臺,And

為什麼你精通CRUD,卻資料庫的基本原理?

原創宣告 本文作者:黃小斜 轉載請務必在文章開頭註明出處和作者。 本文思維導圖 ​ 資料庫和關係型資料庫 作為一個程式設計師,不瞭解資料庫怎麼能行,那麼資料庫到底是個啥呢,作為一個Java工程師,平時和資料庫打交道著實不少,所謂的CRUD其實就是對資料庫進行增刪改查的操作。 根據百度百科的介紹,資料庫是

聽說同學你Java的LinkedHashMap,可笑

先看再點贊,給自己一點思考的時間,微信搜尋【沉默王二】關注這個有顏值卻假裝靠才華苟且的程式設計師。本文 GitHub github.com/itwanger 已收錄,裡面還有我精心為你準備的一線大廠面試題。 同學們好啊,還記得 HashMap 那篇嗎?我自己感覺寫得非常棒啊,既通俗易懂,又深入原始碼,

救救孩子吧,到現在還TCP的三次握手四次揮手

> 本文在個人技術部落格同步釋出,詳情可[**用力戳**](https://www.17coding.info/article/33) > 亦可掃描螢幕右側二維碼關注個人公眾號,公眾號內有個人聯絡方式,等你來撩...   前幾天發了一個朋友圈,發現暗戀已久的女生給我點了個贊,於是我

Spring 學習 2- IOC原理 控制反轉/依賴註入

情況 map return obj 這一 運行 spring入門 lan 設計 控制反轉/依賴註入 最近,買了本spring入門書:spring In Action 。大致瀏覽了下感覺還不錯。就是入門了點。Manning的書還是不錯的,我雖然不像哪些只看Mannin

軟體架構與模式(依賴注入 控制反轉 依賴倒置原則 開閉原則 單一職責原則 介面隔離原則 里氏代換原則)

名詞解釋:   依賴:  一個獨立元素的變化會影響到相關的元素   派生:  一個類是由其他類衍生出的,子類繼承了基類的結構(屬性的名詞和型別)方法   抽象:  去掉每個不重要的細節,專

控制反轉 依賴注入 AOP 和 IOC

一.IOC概念 IOC也成為控制反轉和依賴注入 依賴注入和控制反轉是一個概念,具體講當某個角色需要另外一個角色協助時,在傳統程式設定過程中,需要由呼叫者建立被呼叫者的例項,但在string中建立呼叫者的工作不在由呼叫者完成,因此成為控制反轉。建立者的工作由spring來完成,然後注入到呼叫者

webapi 之 控制反轉/依賴注入

之前在網上看到的webapi注入解決方案五花八門,事實上,有個很簡單的解決方案, 1,下載這個包, 然後在 這個檔案裡面寫你的注入類就好了,其他什麼都不用配置 就是這樣,然後就可以使用建構函式注入了, 完全沒毛病,有問題可以留言。

注入依賴控制反轉的簡單理解

在知乎看到一篇很生動的講解,順便做一下筆記原文地址控制反轉(Inversion of Control,英文縮寫為IoC)把建立物件的權利交給框架,是框架的重要特徵,並非面向物件程式設計的專用術語。它包括依賴注入(Dependency Injection,簡稱DI)和依賴查詢(