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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Play! Framework 系列(四):DI 模式比较

發布時間:2024/1/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Play! Framework 系列(四):DI 模式比较 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文由 Shaw 發表在 ScalaCool 團隊博客。

在 Play! Framework 系列(三)中我們簡單介紹了一下 Play 框架自身支持的兩種依賴注入(運行時依賴注入、編譯時依賴注入)。相信大家對 Play! 的依賴注入應該有所了解了。本文將詳細地介紹一些在日常開發中所采用的依賴注入的方式,以供大家進行合理地選擇。

Guice 和 手動注入

在上一篇文章中我們所介紹的「運行時依賴注入」以及「編譯時依賴注入」就是用的 Guice 以及手動注入,在這里就不作詳細介紹了,大家可以去看看上篇文章以及相應的 Demo

接下來我們介紹比較常用的依賴注入模式。

cake pattern(蛋糕模式)

我們首先介紹一下 Scala 中比較經典的一種依賴注入的模式—— cake pattern(也叫“蛋糕模式”),“蛋糕模式”也屬于「編譯時依賴注入」的一種,她不需要依賴 DI 框架。那 “蛋糕模式” 是如何實現的呢?我們知道,在 Scala 中,多個 trait(特質)能夠 “混入” 到 class 中,這樣在某個 class 中我們就能夠得到所有 trait 中定義的東西了?!暗案饽J健本褪腔诖朔N特性而實現的。

接下來我們就通過一個例子來了解一下“蛋糕模式”:

我們需要在頁面上顯示一個包含所有會員信息的會員列表,需要顯示的內容有:

  • 會員信息
  • 會員卡的信息
  • 需求很簡單,接下來我們用代碼組織一下業務:

    我們需要從數據庫中查詢「會員卡」以及「會員」的信息,所以這里我們首先定義一個數據庫連接的類:DatabaseAccessService 來對相應的數據庫進行操作:

    trait DatabaseAccessServiceComp {val databaseAccessService = new DatabaseAccessService() }class DatabaseAccessService{... } 復制代碼

    大家可能會發現,在我們之前文章中的 service 中并沒有定義 trait,而這里卻定義了,并且在 trait 中,我們實例化了 DatabaseAccessService, 這就是“蛋糕模式”中所需要的,現在看好像并沒有什么卵用,別急,等我們將所有的 service 都定義好了,她就有用了。

    接下來我們定義 WxcardService 以及 WxcardMemberService:

    //定義 WxcardService trait WxcardServiceComp {this: DatabaseAccessServiceComp =>val wxcardService = new WxcardService(databaseAccessService) }class WxcardService(databaseAccessService: DatabaseAccessService) {... }//定義 WxcardMembrService trait WxcardMemberServiceComp {this: DatabaseAccessServiceComp =>val wxcardMemberService = new WxcardMemberService(databaseAccessService) }class WxcardMemberService(databaseAccessService: DatabaseAccessService) {... } 復制代碼

    寫法與上面定義的 DatabaseAccessService 沒有什么區別,因為上面兩個 service 都需要依賴 DatabaseAccessService,所以在特質中用「自身類型」來將其混入,如果需要多個依賴,可以這樣寫:

    this DatabaseAccessServiceComp with BarComp with FooComp => 復制代碼

    最后我們需要定義一個 WxcardController,來將數據傳遞到相應的頁面上去:

    class WxcardController (cc: ControllerComponents,wxcardService: WxcardService,wxcardMemberService: WxcardMemberService ) extends AbstractController(cc) {...} 復制代碼

    可以看到 WxcardController 需要依賴我們上面定義的一些 service,那么在蛋糕模式下,我們怎樣才能將這些依賴注入到 WxcardController 中呢,由于“蛋糕模式”也是「編譯時依賴注入」的一種,那么我們可以參考上一篇文章中所采用的方式:

    同樣,我們需要實現自己的 ApplicationLoader:

    //定義 load 那部分代碼省略了,大家可以去看 Demo ...class MyComponents(context: ApplicationLoader.Context)extends BuiltInComponentsFromContext(context)with play.filters.HttpFiltersComponentswith DatabaseAccessServiceCompwith WxcardServiceCompwith WxcardMemberServiceComp {lazy val wxcardController = new WxcardController(controllerComponents, wxcardService, wxcardMemberService)lazy val router: Router = new Routes(httpErrorHandler, wxcardController) } 復制代碼

    通過上面的代碼,就完成了注入,可以看到我們定義的所有 xxxServiceComp 特質都被混入到了 MyComponents 中,這樣,當 Play加載時,我們所定義的 service 就都在這里被實例化了,為什么呢?因為我們在定義 xxxServiceComp 時,都會有這么一行代碼:

    val xxxService = new XxxService() 復制代碼

    這就是為什么我們之前要在每個 service 中都定義一個 trait,因為 Scala 中的 class 可以混入多個 trait,在這里,我們可以將所有需要的依賴都混入到 MyComponents 中,然后實現注入。

    至于為什么要叫“蛋糕模式”,我個人是這么理解的: 我們定義的 xxxServiceComp 比如 WxcardServiceComp 相當于蛋糕中的某一層,而那些需要被多次依賴的 xxxServiceComp,比如上面定義的 DatabaseAccessServiceComp 可以看作是蛋糕中的調味料(比如水果,巧克力啥的),將這些蛋糕一層一層地放在一起,然后再混入一些調味料,就組成了一個大的蛋糕—— MyComponents。

    可以看到“蛋糕模式”中,我們需要寫非常多的樣板代碼,要為每個 service 都定義一個 trait,感覺心很累,那么接下來我們就介紹一種比較輕巧而又簡潔的的方式。

    macwire

    macwire 是基于 「Scala 宏」來實現的,我們使用她可以讓依賴注入變得非常簡單,并且使我們的代碼量減少許多。接下來,我們就通過 macwire 來實現一下上面的例子。

    首先在項目中引入 macwire,在 build.sbt 文件中增加一行依賴:

    libraryDependencies ++= Seq("org.scalatestplus.play" %% "scalatestplus-play" % "3.0.0-M3" % Test,//在這里添加 macwire 的依賴"com.softwaremill.macwire" %% "macros" % "2.3.0" % Provided, ) 復制代碼

    然后定義 service:

    //定義 DatabaseAccessServiceclass DatabaseAccessService{... }//定義 WxcardServiceclass WxcardService(databaseAccessService: DatabaseAccessService) {... }//定義 WxcardMembrServiceclass WxcardMemberService(databaseAccessService: DatabaseAccessService) {... } 復制代碼

    可以看到,我們現在就不需要定義 trait 了,接下來,定義 WxcardController:

    class WxcardController (cc: ControllerComponents,wxcardService: WxcardService,wxcardMemberService: WxcardMemberService ) extends AbstractController(cc) {...} 復制代碼

    controller 的定義和上面的一樣,接下來,我們就使用 macwire 來實現依賴注入,macwire 也是「編譯時依賴注入」的一種,所以我們同樣需要實現 ApplicationLoader:

    import com.softwaremill.macwire._ ...class MyComponents(context: ApplicationLoader.Context)extends BuiltInComponentsFromContext(context)with play.filters.HttpFiltersComponents {lazy val databaseAccessService = wire[DatabaseAccessService]lazy val wxcardService = wire[WxcardService]lazy val wxcardMemberService = wire[WxcardMemberService]lazy val wxcardController = wire[WxcardController]lazy val router: Router = {val prefix = "/"wire[Routes]} } 復制代碼

    在上面的代碼中,我們只需要將相應的依賴通過下面的方式實例化就可以了:

    lazy val wxcardService = wire[WxcardService] 復制代碼

    就是在類型外面添加了一個 wire,這樣就完成了實例化,并且也不需要指定依賴的參數,macwire 會自動幫我們完成實例化和注入:

    比如上面的

    lazy val databaseAccessService = wire[DatabaseAccessService] lazy val wxcardService = wire[WxcardService] lazy val wxcardMemberService = wire[WxcardMemberService] lazy val wxcardController = wire[WxcardController] 復制代碼

    macwire 就幫我們轉化成了:

    lazy val databaseAccessService = new DatabaseAccessService() lazy val wxcardService = new WxcardService(databaseAccessService) lazy val wxcardMemberService = new WxcardMemberService(databaseAccessService) lazy val wxcardController = new WxcardController(controllerComponents, wxcardService, wxcardMemberService) 復制代碼

    我們只需要在定義某個類的時候聲明我們需要哪些依賴,實例化和注入 macwire 都會幫我們去完成,macwire 在實例化某個類的時候,會去當前文件或者與當前文件有關的代碼中查找相關的依賴,找到了就完成注入,若沒有找到說明該依賴沒有被定義過,或者沒有正確引入。

    在日常開發中,我們會創建很多個 service,將所有的 service 放在 MyComponents 中實例化會使得代碼顯得很臃腫,而且也不便于維護。通常我們會專門定義一個 Module 來組織這些 service:

    package configimport com.softwaremill.macwire._ import services._trait ServicesModule {lazy val databaseAccessService = wire[DatabaseAccessService]lazy val wxcardService = wire[WxcardService]lazy val wxcardMemberService = wire[WxcardMemberService] }復制代碼

    這里我們新建了一個 ServiceModule.scala 文件來將組織這些 service。

    那么上面的 ApplicationLoader 文件就可以這樣去寫:

    import com.softwaremill.macwire._ ...class MyComponents(context: ApplicationLoader.Context)extends BuiltInComponentsFromContext(context)with play.filters.HttpFiltersComponentswith config.ServicesModule {lazy val wxcardController = wire[WxcardController]lazy val router: Router = {val prefix = "/"wire[Routes]} } 復制代碼

    可以看到 macwire 使用起來非常簡單,并且能夠簡化我們的依賴注入。在我們的項目中所采用的是 macwire,所以推薦大家使用 macwire。

    結語

    關于 Play 中的「依賴注入」到這里就結束了,希望能夠給大家一些幫助,另外 Play 系列的文章從上一篇到現在拖了太久了,非常抱歉,感謝一直以來的關注,后面我會加快寫作節奏的,本文的例子請戳源碼鏈接。

    總結

    以上是生活随笔為你收集整理的Play! Framework 系列(四):DI 模式比较的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 午夜亚洲天堂 | 久久精品牌麻豆国产大山 | 国产原创剧情av | 久久国产精品久久国产精品 | 三上悠亚在线观看一区二区 | 天天干天天操av | 国产乱码一区二区三区播放 | 91亚洲精品国偷拍自产在线观看 | 日韩人妻无码精品综合区 | 色爱区综合 | 久久在线免费观看视频 | 精品久久ai| 黄色香蕉视频 | 五月丁香啪啪 | 大桥未久av一区二区三区中文 | 激情文学综合网 | 黑人粗进入欧美aaaaa | 欧美不卡在线观看 | 午夜插插| 国产欧美精品一区二区三区app | 日韩美一区二区三区 | 久久久国产亚洲 | 色综合久久久久久久 | 欧美亚洲精品一区二区 | 国产成人精品一区二区在线观看 | 国产精品免费视频观看 | 在线观看黄色的网站 | 欧美精品影院 | 老版k8经典电影 | 可以免费观看的av | 国产成人aaa| 毛片看看| 精品久久久久久久久久久久久 | 无码aⅴ精品一区二区三区浪潮 | 四级毛片 | 成年男女免费视频网站 | 成人免费一级 | 狼色网 | 天堂在线观看中文字幕 | 亚洲第一成年网 | 国产精品美女久久久久久久 | 91蜜桃在线 | 精品乱码一区二区三四区视频 | 国产精品久久久久久久久久小说 | 国内av网站 | 欧美另类天堂 | 精品欧美一区二区在线观看 | 亚洲热热| 妺妺窝人体色www在线下载 | 国产r级在线观看 | 日本久草视频 | 亚洲福利小视频 | 最近的中文字幕 | 伊人国产在线视频 | 久久99精品久久久久子伦 | 黄色调教视频 | 99久久婷婷国产精品综合 | 亚洲人精品午夜射精日韩 | jizz视频| 乱中年女人伦 | 日本爽爽 | 毛片av网址 | 五月综合激情日本mⅴ | 黄色自拍网站 | 国产人成在线观看 | 五月婷婷天 | 亚洲精品久久久乳夜夜欧美 | 日韩1页 | 国产人伦精品一区二区三区 | 国产在线欧美在线 | 在线免费观看a视频 | 欧美黄色性视频 | 中文在线最新版天堂8 | 欧美日韩3p | a级成人毛片 | 午夜成人免费视频 | 后进极品美女圆润翘臀 | 国产一区二区电影 | 成年人在线观看网站 | 欧美日韩1 | 草免费视频| 亚洲激情啪啪 | 免费污片在线观看 | 亚洲精品午夜国产va久久成人 | 女女av在线 | 杨贵妃颤抖双乳呻吟求欢小说 | 国产精品一二三 | 看黄网站在线观看 | 日本xxxx高清| 成人毛片a| 欧美特黄色片 | 韩国精品一区二区三区 | 黄色高潮视频 | 男女插插视频 | 人人草在线视频 | 国产成人三级在线 | 琪琪色在线观看 | 东方av在线免费观看 | 关之琳三级全黄做爰在线观看 |