日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

程序员过关斩将--错误的IOC和DI

發(fā)布時(shí)間:2023/12/4 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员过关斩将--错误的IOC和DI 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是IOC?

什么是DI?

IOC和DI有什么關(guān)系?

作為程序員,天天擼代碼,怎么能不知道IOC和DI呢。很多面試官也喜歡問(wèn)這兩個(gè)概念,雖然概念很簡(jiǎn)單,但是可以從面試者的回答當(dāng)中,大體的可以估算到面試者的功力,那IOC和DI到底是何方神圣呢?讓我們來(lái)一步一步扒掉它的外衣!!

說(shuō)到IOC和DI,必須要提一下軟件設(shè)計(jì)的六大原則

單一職責(zé)原則

一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因

開(kāi)閉原則

軟件實(shí)體應(yīng)該是可擴(kuò)展,而不可修改的。也就是說(shuō),對(duì)擴(kuò)展是開(kāi)放的,而對(duì)修改是封閉的。這個(gè)原則是諸多面向?qū)ο缶幊淘瓌t中最抽象、最難理解的一個(gè)。

里氏替換原則

所有引用基類的地方必須能透明地使用其子類的對(duì)象,換句話說(shuō),子類在任何引用基類的地方都可以替換成子類。

依賴倒置原則

這個(gè)原則說(shuō)的詳細(xì)一點(diǎn)其實(shí)可以概括為兩點(diǎn):

  • 高層模塊不應(yīng)該直接依賴于底層模塊,應(yīng)該依賴于抽象

  • 抽象不應(yīng)該依賴于具體實(shí)現(xiàn),具體實(shí)現(xiàn)應(yīng)該依賴于抽象

  • 接口隔離原則

    程序不依賴于不使用的接口,換句話說(shuō),一個(gè)程序只依賴于它需要的接口。

    我在之前的很多文章中也多次提到,要想系統(tǒng)保持高擴(kuò)展性,始終離不開(kāi)對(duì)業(yè)務(wù)的深刻理解和抽象

    論系統(tǒng)設(shè)計(jì)的高可擴(kuò)展性

    IOC

    控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來(lái)減低計(jì)算機(jī)代碼之間的耦合度

    以上是IOC最典型的概念定義,其中“控制”這個(gè)詞具有很泛的概念,比如:控制對(duì)象的初始化,控制程序的流程,控制資源的生命周期...等等,反轉(zhuǎn)就和表面意思一樣比較好理解,就是反過(guò)來(lái)。控制和反轉(zhuǎn)綜合起來(lái)呢,可以概括為:

    對(duì)于程序的行為,把控制權(quán)交給其他人

    確實(shí)不好理解,因?yàn)樯厦孢@句話是我自己總結(jié)的,說(shuō)實(shí)話,我自己咋一聽(tīng)到都理解不了。還是舉個(gè)栗子吧:

    最常見(jiàn)并且最常用的莫過(guò)于類的使用,如下代碼:

    class?A {public?void?XXOO(){} }class?Main {A?a=new?A();a.XXOO(); }

    上面的代碼我想在我們平時(shí)的coding過(guò)程中非常多,那有什么問(wèn)題嗎?還是那句話,從功能性的角度來(lái)說(shuō),只存在正確和錯(cuò)誤的觀點(diǎn),但是從非功能性的角度來(lái)說(shuō),每個(gè)人有每個(gè)人的見(jiàn)解。有的人不喜歡代碼中中到處充斥著New的味道,有的人卻喜歡掌控自己的代碼(因?yàn)樽约簩懙腘ew,自己最清楚)。

    至于軟件編寫的對(duì)與錯(cuò),并沒(méi)有一個(gè)明確的規(guī)范去說(shuō)明,但是軟件從小到大,從簡(jiǎn)單需求到越來(lái)越多的需求,把軟件開(kāi)發(fā)過(guò)程中一些不爽的詬病提取出來(lái)并解決,就是軟件質(zhì)量提升的一個(gè)度量角度。

    言歸正傳,上面的代碼以多數(shù)程序員的角度來(lái)說(shuō),不喜歡到處有New這個(gè)關(guān)鍵字,就好像New多了會(huì)出Bug一樣!!為什么好多架構(gòu)師不推薦到處有New的味道?我認(rèn)為并不是代碼美不美觀,能不能裝X的問(wèn)題,是因?yàn)檐浖軜?gòu)層次中強(qiáng)依賴的關(guān)系。

    那怎么破除強(qiáng)依賴呢?

    DI(依賴注入)

    與IOC不同,DI是一種具體的編碼技巧。但是,它并非為了解決New的問(wèn)題而生,而是為了解決軟件架構(gòu)層面的問(wèn)題而生,其實(shí),從大多數(shù)使用場(chǎng)景來(lái)說(shuō),DI確實(shí)可以看做是實(shí)現(xiàn)IOC的一種解決方案。

    有的架構(gòu)師說(shuō),依賴注入就是把類放到容器當(dāng)中,然后解析這些類的實(shí)例。我不否認(rèn)原理上確實(shí)是容器來(lái)負(fù)責(zé)管理有依賴關(guān)系的模塊或者類(接口),但是依賴注入在依賴關(guān)系上其實(shí)在為了解耦和多態(tài)。

    說(shuō)到這里,突然想起一件小事,作為高大上工作的開(kāi)發(fā)者,都已經(jīng)跨入21世界20多個(gè)年頭了,還在圍繞著數(shù)據(jù)庫(kù)進(jìn)行coding,在沒(méi)有表的情況下居然沒(méi)辦法開(kāi)展工作?我并不排斥圍繞數(shù)據(jù)庫(kù)進(jìn)行設(shè)計(jì)編碼,因?yàn)楹芏嘟y(tǒng)計(jì)類的需求確實(shí)需要這樣,但是大多數(shù)業(yè)務(wù)不應(yīng)該是圍繞業(yè)務(wù)來(lái)開(kāi)展編碼嗎?沒(méi)有數(shù)據(jù)庫(kù)就不能進(jìn)行coding是不是該改一改了?

    依賴注入會(huì)在架構(gòu)的擴(kuò)展點(diǎn)出現(xiàn),一個(gè)好的軟件架構(gòu),永遠(yuǎn)會(huì)在需要擴(kuò)展的地方提供自定義入口,說(shuō)直白一點(diǎn),任何一個(gè)系統(tǒng)都應(yīng)該在會(huì)變化的地方進(jìn)行抽象。舉一個(gè)簡(jiǎn)單例子:一個(gè)支付系統(tǒng)會(huì)存在多種支付方式:微信、支付寶、銀聯(lián)等等。這些不同的支付方式其實(shí)就可以看做是系統(tǒng)的變化點(diǎn),應(yīng)該把這個(gè)地方進(jìn)行抽象,并花大量精力去好好設(shè)計(jì)。

    重點(diǎn)問(wèn)題

    那么問(wèn)題來(lái)了:如果我沒(méi)有使用面向接口(interface)進(jìn)行開(kāi)發(fā),代碼的分層一律都是以類(Class)來(lái)組織的,類似于以下代碼:

    ?var?ret?=?await?UserService.SetDefaultUserPlan(para.UserId,?para.UserPlanId);

    那我的類UserService是否也應(yīng)該進(jìn)行依賴注入呢?類似于以下代碼(DI框架可能不一樣,但是原理都是相同的)

    ?services.AddSingleton<UserService,?UserService>();

    我想這個(gè)問(wèn)題,每個(gè)人也都有自己的見(jiàn)解。有很多人認(rèn)為,DI解決的是到處充斥著New味道的問(wèn)題,每個(gè)類都應(yīng)該進(jìn)行DI操作,這樣的代碼才夠“簡(jiǎn)潔,漂亮”。

    是嗎?

    針對(duì)于以上觀點(diǎn),我其實(shí)有話要說(shuō)。還是本質(zhì)問(wèn)題的討論,DI到底要解決軟件開(kāi)發(fā)中的什么問(wèn)題呢?是New的問(wèn)題嗎?不,是解耦、擴(kuò)展、依賴的問(wèn)題。

    說(shuō)道這三個(gè)非功能性的指標(biāo),其實(shí)和上邊講的幾大軟件設(shè)計(jì)規(guī)則息息相關(guān),無(wú)論是什么樣的軟件系統(tǒng)都擺脫不了業(yè)務(wù)變化的命運(yùn)。有的程序員最害怕這種變化,因?yàn)橐坏┌l(fā)生業(yè)務(wù)變化,他就要改動(dòng)大量的代碼,接連會(huì)產(chǎn)生大量的Bug,進(jìn)而會(huì)加大量的班。

    其實(shí),面對(duì)變化的時(shí)候,如果發(fā)生以上情況,我們應(yīng)該反思自己是不是沒(méi)有把業(yè)務(wù)的變化點(diǎn)分析清楚。還是拿支付業(yè)務(wù)為例,假如系統(tǒng)開(kāi)始只有微信支付,可能你的代碼很像以下這種

    ?public?void?Pay(int?amount){//微信支付WXPay.Pay(amount);}

    隨著時(shí)間推移,公司業(yè)務(wù)發(fā)展壯大,產(chǎn)品上要支持支付寶支付,你的代碼很大概率會(huì)變成這樣

    ?public?void?Pay(int?payMode,?int?amount){if?(payMode?==?"微信支付"){//微信支付WXPay.Pay(amount);}else?if?(payMode?==?"支付寶支付"){//支付寶支付AliPay.Pay(amout);}}

    如果隨著業(yè)務(wù)繼續(xù)發(fā)展,產(chǎn)品上又陸續(xù)加入了很多支付方式,你的代碼就會(huì)變成以下這種方式

    ?public?void?Pay(int?payMode,?int?amount){if?(payMode?==?"微信支付"){//微信支付WXPay.Pay(amount);}else?if?(payMode?==?"支付寶支付"){//支付寶支付AliPay.Pay(amout);}else?if?(payMode?==?"XX支付"){//支付寶支付XXXPay.Pay(amout);}else?if?(payMode?==?"YY支付"){//支付寶支付YYPay.Pay(amout);}...}

    大量的if-else,很多人稱之為“壞代碼”味道(其實(shí)這樣的代碼每個(gè)公司都有)。通過(guò)這個(gè)例子其實(shí)大家已經(jīng)看出來(lái)了,支付方式這是一個(gè)業(yè)務(wù)的變化點(diǎn),應(yīng)該在這個(gè)業(yè)務(wù)點(diǎn)上做抽象了。這個(gè)時(shí)候所謂的面向接口編程正是解決之道,其實(shí)也可以理解為程序的多態(tài)性:

    ?interface?IPay{void?Pay(int?amount);}

    然后每次新加一種支付方式,去實(shí)現(xiàn)這個(gè)接口,然后利用DI操作一下。在業(yè)務(wù)發(fā)生變化的過(guò)程中,根據(jù)某種策略來(lái)實(shí)現(xiàn)對(duì)應(yīng)的支付方式即可。

    在這個(gè)例子中,利用DI技術(shù)不僅解決了依賴倒置原則,更解決了系統(tǒng)擴(kuò)展性的問(wèn)題。回到開(kāi)頭的問(wèn)題,為了解決New的美觀問(wèn)題,到底應(yīng)不應(yīng)該使用DI呢?其實(shí)我不推薦

    寫在最后

    關(guān)于上邊的問(wèn)題,歡迎來(lái)噴,畢竟知識(shí)需要討論才能進(jìn)步

    總結(jié)

    以上是生活随笔為你收集整理的程序员过关斩将--错误的IOC和DI的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。