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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

di容器_DI容器是代码污染者

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 di容器_DI容器是代码污染者 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

di容器

盡管依賴項注入 (aka,“ DI”)是一種在OOP中組成對象的自然技術(在Martin Fowler引入該術語之前就已知道),但Spring IoC , Google Guice , Java EE6 CDI , Dagger和其他DI框架將其轉變為反模式。

我將不討論反對“ setter注入”(例如在Spring IoC中 )和“現場注入”(例如在PicoContainer中 )的明顯論點。 這些機制只是違反了面向對象編程的基本原理,并鼓勵我們創建不完整的可變對象,這些對象在應用程序執行過程中會塞滿數據。 請記住:理想對象必須是不可變的 , 并且不能包含setter 。


相反,讓我們討論“構造函數注入”(例如Google Guice中的方法 )及其與依賴項注入容器的結合使用 。 我將嘗試表明為什么至少將這些容器視為冗余。

什么是依賴注入?

這就是依賴項注入(與普通的舊對象組成沒有真正的區別):

public class Budget {private final DB db;public Budget(DB data) {this.db = data;}public long total() {return this.db.cell("SELECT SUM(cost) FROM ledger");} }

對象data稱為“依賴關系”。

Budget不知道它正在使用哪種數據庫。 它需要從數據庫中獲得的所有功能,就是能夠通過cell()方法使用任意SQL查詢來獲取單元cell() 。 我們可以使用DB接口的PostgreSQL實現實例化Budget ,例如:

public class App {public static void main(String... args) {Budget budget = new Budget(new Postgres("jdbc:postgresql:5740/main"));System.out.println("Total is: " + budget.total());} }

換句話說,我們正在將依賴項“注入”到新的對象budget 。

這種“依賴注入”方法的替代方法是讓Budget決定要使用的數據庫:

public class Budget {private final DB db = new Postgres("jdbc:postgresql:5740/main");// class methods }

這非常臟,導致1)代碼重復,2)無法重用和3)無法測試等。無需討論原因。 很明顯。

因此,通過構造函數進行依賴注入是一種了不起的技術。 好吧,甚至沒有一種技術。 更像Java和所有其他面向對象語言的功能。 預計幾乎所有對象都希望封裝一些知識(也稱為“狀態”)。 這就是構造函數的用途。

什么是DI容器?

到目前為止,一切都很好,但是這里面是陰暗的一面-依賴項注入容器。 它是這樣工作的(讓我們以Google Guice為例):

import javax.inject.Inject; public class Budget {private final DB db;@Injectpublic Budget(DB data) {this.db = data;}// same methods as above }

注意:構造函數帶有@Inject注釋。

然后,我們應該在應用程序啟動時在某處配置一個容器:

Injector injector = Guice.createInjector(new AbstractModule() {@Overridepublic void configure() {this.bind(DB.class).toInstance(new Postgres("jdbc:postgresql:5740/main"));}} );

一些框架甚至允許我們在XML文件中配置注入器。

從現在開始,我們將無法像以前一樣通過new運算符實例化Budget 。 相反,我們應該使用剛剛創建的注射器:

public class App {public static void main(String... args) {Injection injector = // as we just did in the previous snippetBudget budget = injector.getInstance(Budget.class);System.out.println("Total is: " + budget.total());} }

注入自動發現,要實例化Budget它必須為其構造函數提供一個參數。 它將使用我們在注入器中實例化的Postgres類的實例。

這是使用Guice的正確和推薦的方法。 但是,有一些甚至更暗的模式,這是可能的,但不建議這樣做。 例如,您可以使噴射器成為單例,并直接在Budget類中使用它。 這些機制甚至被DI容器制造商都認為是錯誤的,因此,讓我們忽略它們,重點關注推薦的方案。

這個是來做什么的?

讓我重申并總結不正確使用依賴項注入容器的場景:

  • 現場注入
  • 二傳手注射
  • 將注入器作為依賴項
  • 使注入器成為全局單例

如果我們將它們全部放在一邊,剩下的就是上面解釋的構造函數注入。 那對我們有什么幫助? 我們為什么需要它? 為什么我們不能在應用程序的主類中使用普通的new ?

如果使用XML,我們創建的容器只是向代碼庫添加了更多行,甚至添加了更多文件。 它除了增加了復雜性之外沒有增加任何東西。 如果遇到以下問題,我們應該永遠記住這一點:“哪個數據庫用作預算的論點?”

正確的方式

現在,讓我向您展示一個使用new構造應用程序的真實示例。 這是我們在rultor.com中創建“思維引擎”的方式 (完整的類在Agents.java ):

final Agent agent = new Agent.Iterative(new Array(new Understands(this.github,new QnSince(49092213,new QnReferredTo(this.github.users().self().login(),new QnParametrized(new Question.FirstOf(new Array(new QnIfContains("config", new QnConfig(profile)),new QnIfContains("status", new QnStatus(talk)),new QnIfContains("version", new QnVersion()),new QnIfContains("hello", new QnHello()),new QnIfCollaborator(new QnAlone(talk, locks,new Question.FirstOf(new Array(new QnIfContains("merge",new QnAskedBy(profile,Agents.commanders("merge"),new QnMerge())),new QnIfContains("deploy",new QnAskedBy(profile,Agents.commanders("deploy"),new QnDeploy())),new QnIfContains("release",new QnAskedBy(profile,Agents.commanders("release"),new QnRelease())))))))))))),new StartsRequest(profile),new RegistersShell("b1.rultor.com", 22,"rultor",IOUtils.toString(this.getClass().getResourceAsStream("rultor.key"),CharEncoding.UTF_8)),new StartsDaemon(profile),new KillsDaemon(TimeUnit.HOURS.toMinutes(2L)),new EndsDaemon(),new EndsRequest(),new Tweets(this.github,new OAuthTwitter(Manifests.read("Rultor-TwitterKey"),Manifests.read("Rultor-TwitterSecret"),Manifests.read("Rultor-TwitterToken"),Manifests.read("Rultor-TwitterTokenSecret"))),new CommentsTag(this.github),new Reports(this.github),new RemovesShell(),new ArchivesDaemon(new ReRegion(new Region.Simple(Manifests.read("Rultor-S3Key"),Manifests.read("Rultor-S3Secret"))).bucket(Manifests.read("Rultor-S3Bucket"))),new Publishes(profile)) );

印象深刻? 這是真正的對象組成。 我相信這是應該實例化正確的面向對象應用程序的方式。

和DI容器? 我認為,它們只會增加不必要的噪音。

相關文章

您可能還會發現以下有趣的帖子:

  • Getters / Setters。 邪惡。 期。
  • OOP中的反模式
  • 避免字符串串聯
  • 對象應該是不可變的
  • 為什么NULL是錯誤的?

翻譯自: https://www.javacodegeeks.com/2014/10/di-containers-are-code-polluters.html

di容器

總結

以上是生活随笔為你收集整理的di容器_DI容器是代码污染者的全部內容,希望文章能夠幫你解決所遇到的問題。

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