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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/4 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员过关斩将--错误的IOC和DI 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是IOC?

什么是DI?

IOC和DI有什么關系?

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

說到IOC和DI,必須要提一下軟件設計的六大原則

單一職責原則

一個類應該只有一個發生變化的原因

開閉原則

軟件實體應該是可擴展,而不可修改的。也就是說,對擴展是開放的,而對修改是封閉的。這個原則是諸多面向對象編程原則中最抽象、最難理解的一個。

里氏替換原則

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

依賴倒置原則

這個原則說的詳細一點其實可以概括為兩點:

  • 高層模塊不應該直接依賴于底層模塊,應該依賴于抽象

  • 抽象不應該依賴于具體實現,具體實現應該依賴于抽象

  • 接口隔離原則

    程序不依賴于不使用的接口,換句話說,一個程序只依賴于它需要的接口。

    我在之前的很多文章中也多次提到,要想系統保持高擴展性,始終離不開對業務的深刻理解和抽象

    論系統設計的高可擴展性

    IOC

    控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度

    以上是IOC最典型的概念定義,其中“控制”這個詞具有很泛的概念,比如:控制對象的初始化,控制程序的流程,控制資源的生命周期...等等,反轉就和表面意思一樣比較好理解,就是反過來??刂坪头崔D綜合起來呢,可以概括為:

    對于程序的行為,把控制權交給其他人

    確實不好理解,因為上面這句話是我自己總結的,說實話,我自己咋一聽到都理解不了。還是舉個栗子吧:

    最常見并且最常用的莫過于類的使用,如下代碼:

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

    上面的代碼我想在我們平時的coding過程中非常多,那有什么問題嗎?還是那句話,從功能性的角度來說,只存在正確和錯誤的觀點,但是從非功能性的角度來說,每個人有每個人的見解。有的人不喜歡代碼中中到處充斥著New的味道,有的人卻喜歡掌控自己的代碼(因為自己寫的New,自己最清楚)。

    至于軟件編寫的對與錯,并沒有一個明確的規范去說明,但是軟件從小到大,從簡單需求到越來越多的需求,把軟件開發過程中一些不爽的詬病提取出來并解決,就是軟件質量提升的一個度量角度。

    言歸正傳,上面的代碼以多數程序員的角度來說,不喜歡到處有New這個關鍵字,就好像New多了會出Bug一樣!!為什么好多架構師不推薦到處有New的味道?我認為并不是代碼美不美觀,能不能裝X的問題,是因為軟件架構層次中強依賴的關系。

    那怎么破除強依賴呢?

    DI(依賴注入)

    與IOC不同,DI是一種具體的編碼技巧。但是,它并非為了解決New的問題而生,而是為了解決軟件架構層面的問題而生,其實,從大多數使用場景來說,DI確實可以看做是實現IOC的一種解決方案。

    有的架構師說,依賴注入就是把類放到容器當中,然后解析這些類的實例。我不否認原理上確實是容器來負責管理有依賴關系的模塊或者類(接口),但是依賴注入在依賴關系上其實在為了解耦和多態。

    說到這里,突然想起一件小事,作為高大上工作的開發者,都已經跨入21世界20多個年頭了,還在圍繞著數據庫進行coding,在沒有表的情況下居然沒辦法開展工作?我并不排斥圍繞數據庫進行設計編碼,因為很多統計類的需求確實需要這樣,但是大多數業務不應該是圍繞業務來開展編碼嗎?沒有數據庫就不能進行coding是不是該改一改了?

    依賴注入會在架構的擴展點出現,一個好的軟件架構,永遠會在需要擴展的地方提供自定義入口,說直白一點,任何一個系統都應該在會變化的地方進行抽象。舉一個簡單例子:一個支付系統會存在多種支付方式:微信、支付寶、銀聯等等。這些不同的支付方式其實就可以看做是系統的變化點,應該把這個地方進行抽象,并花大量精力去好好設計。

    重點問題

    那么問題來了:如果我沒有使用面向接口(interface)進行開發,代碼的分層一律都是以類(Class)來組織的,類似于以下代碼:

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

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

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

    我想這個問題,每個人也都有自己的見解。有很多人認為,DI解決的是到處充斥著New味道的問題,每個類都應該進行DI操作,這樣的代碼才夠“簡潔,漂亮”。

    是嗎?

    針對于以上觀點,我其實有話要說。還是本質問題的討論,DI到底要解決軟件開發中的什么問題呢?是New的問題嗎?不,是解耦、擴展、依賴的問題。

    說道這三個非功能性的指標,其實和上邊講的幾大軟件設計規則息息相關,無論是什么樣的軟件系統都擺脫不了業務變化的命運。有的程序員最害怕這種變化,因為一旦發生業務變化,他就要改動大量的代碼,接連會產生大量的Bug,進而會加大量的班。

    其實,面對變化的時候,如果發生以上情況,我們應該反思自己是不是沒有把業務的變化點分析清楚。還是拿支付業務為例,假如系統開始只有微信支付,可能你的代碼很像以下這種

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

    隨著時間推移,公司業務發展壯大,產品上要支持支付寶支付,你的代碼很大概率會變成這樣

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

    如果隨著業務繼續發展,產品上又陸續加入了很多支付方式,你的代碼就會變成以下這種方式

    ?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,很多人稱之為“壞代碼”味道(其實這樣的代碼每個公司都有)。通過這個例子其實大家已經看出來了,支付方式這是一個業務的變化點,應該在這個業務點上做抽象了。這個時候所謂的面向接口編程正是解決之道,其實也可以理解為程序的多態性:

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

    然后每次新加一種支付方式,去實現這個接口,然后利用DI操作一下。在業務發生變化的過程中,根據某種策略來實現對應的支付方式即可。

    在這個例子中,利用DI技術不僅解決了依賴倒置原則,更解決了系統擴展性的問題?;氐介_頭的問題,為了解決New的美觀問題,到底應不應該使用DI呢?其實我不推薦

    寫在最后

    關于上邊的問題,歡迎來噴,畢竟知識需要討論才能進步

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。