<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 使用依賴注入設(shè)計(jì)更好的代碼

          共 3780字,需瀏覽 8分鐘

           ·

          2020-09-14 19:38

          點(diǎn)擊上方藍(lán)色“Golang來(lái)啦”關(guān)注我喲

          加個(gè)“星標(biāo)”,天天 15 分鐘,掌握?Go 語(yǔ)言

          via:
          https://medium.com/effective-development/building-better-software-in-go-with-di-faf8301a9f84


          作者:Sergey Suslov

          四哥水平有限,如有翻譯或理解錯(cuò)誤,煩請(qǐng)幫忙指出,感謝!

          原文如下:


          在這篇文章中,我將簡(jiǎn)單介紹下什么是 SOLID 理論、什么是依賴注入(DI)以及如何運(yùn)用它們?nèi)ゾ帉懜玫拇a。我們會(huì)演示很多的的代碼示例。本文的重點(diǎn)是展示如何使用 DI 和 SOLID 編寫更具測(cè)試性和高可用的代碼。

          什么是 SOLID?

          SOLID 是 Robert Martin 在他的書中提出的一組原則:

          • 單一職責(zé)原則(S)

          • 開(kāi)閉原則(O)

          • 里氏替換原則(L)

          • 接口分離原則(I)

          • 依賴倒置原則(D)

          上面這些原則可以幫助我們編寫更好的代碼,今天我們只會(huì)介紹第一條和最后一條原則。

          依賴倒置原則(DIP)

          這條原則是說(shuō)軟件模塊應(yīng)該依賴于抽象而不依賴于具體的實(shí)現(xiàn),這樣才能設(shè)計(jì)更具靈活性的系統(tǒng)。

          一起來(lái)看下下面這個(gè)例子:

          在這個(gè)圖上,可以看到有兩個(gè)類 ClientService 和 PostgresClientRepository。我們假設(shè) ClientService 包含業(yè)務(wù)邏輯,通過(guò) PostgresClientRepository 類可以操作 PostgreSQL。ClientService 依賴于 PostgresClientRepository。

          代碼如下:

          type?PostgresClientRepository?struct?{
          }

          func?(c?PostgresClientRepository)?Do()?{
          ???log.Println("Done")
          }

          type?ClientService?struct?{
          ???clientRepository?PostgresClientRepository
          }

          上面這種代碼設(shè)計(jì)違背了依賴倒置原則(DIP),因?yàn)?ClientService 依賴于具體的實(shí)現(xiàn)。這種關(guān)系一定程度上限制了我們?nèi)バ薷?PostgresClientRepository 類,降低了代碼靈活性。

          基于依賴倒置原則(DIP),解決辦法如下:

          現(xiàn)在,這兩個(gè)類都依賴于 ClientRepository 接口,ClientService 依賴于穩(wěn)定的接口 ClientRepository,它可以基于該接口實(shí)現(xiàn)自己想要的東西。PostgresClientRepository 也依賴于該接口,并且可以保持其靈活性。

          修改之后代碼如下:

          type?ClientRepository?interface?{
          ???Do()
          }

          type?PostgresClientRepository?struct?{
          }

          func?(c?PostgresClientRepository)?Do()?{
          ???log.Println("Done")
          }

          type?ClientService?struct?{
          ???clientRepository?ClientRepository
          }

          單一職責(zé)原則(SRP)

          這個(gè)原則是說(shuō)一個(gè)模塊只有一個(gè)理由去修改,換句話說(shuō),一個(gè)模塊只需要承擔(dān)唯一的職責(zé)。(ps:各種邏輯處理不能冗雜在一個(gè)函數(shù)里面,一個(gè)函數(shù)完成一項(xiàng)功能即可)。

          這樣做是為了實(shí)現(xiàn):

          • 測(cè)試更方便;

          • 減少改動(dòng)代碼之后模塊之間相互影響;

          讓我給你舉個(gè)例子,這個(gè)原則是如何使生活變得更美好的。讓我們假設(shè)現(xiàn)在有一個(gè)接口和它的實(shí)現(xiàn),ClientRepository 是接口,ClientRepositoryImpl是它的實(shí)現(xiàn)。

          type?ClientRepository?interface?{
          ???Do()
          }

          type?ClientRepositoryImpl?struct?{
          }

          func?(c?ClientRepositoryImpl)?Do()?{
          ???log.Println("Done")
          }

          現(xiàn)在來(lái)看下基于 ClientRepository 及其構(gòu)造函數(shù)提供的服務(wù)。

          type?ClientService?struct?{
          ???clientRepository?ClientRepository
          }

          func?NewClientService()?*ClientService?{
          ???return?&ClientService{clientRepository:?ClientRepositoryImpl{}}
          }

          這個(gè)構(gòu)造函數(shù)違背了單一職責(zé)原則(SRP),它不應(yīng)該負(fù)責(zé)創(chuàng)建 ClientRepository。作為 ClientService 的一部分,這個(gè)構(gòu)造函數(shù)決定了 ClientRepository 的具體實(shí)現(xiàn)。

          這非常糟糕,作為開(kāi)發(fā)人員,如果我們想換一種實(shí)現(xiàn)方式就必須重寫構(gòu)造函數(shù);另外,在測(cè)試的時(shí)候也如法模擬 clientRepository。

          這個(gè)問(wèn)題的解決辦法很明顯:

          type?ClientService?struct?{
          ???clientRepository?ClientRepository
          }

          func?NewClientService(clientRepository?ClientRepository)?*ClientService?{
          ???return?&ClientService{clientRepository}
          }

          但是,這個(gè)解決辦法有個(gè)新的問(wèn)題,想要?jiǎng)?chuàng)建 ClientService,必須自己先創(chuàng)建 ClientRepository 并將其作為參數(shù)傳遞給構(gòu)造函數(shù)。

          這就是依賴注入(DI)可以提供極大幫助的地方。

          依賴注入機(jī)制

          依賴注入是一種對(duì)象接收其所依賴的對(duì)象的技術(shù)。

          Uber dig 就是一個(gè)強(qiáng)大易用的 DI 工具包,并且提供了很多好的示例。

          這個(gè)包提供了兩個(gè)主要的函數(shù),第一個(gè)就是 Provide,允許我們定義自己的依賴項(xiàng)。

          通過(guò) Provide 方法將不同類型的構(gòu)造函數(shù)添加到容器里面。構(gòu)造函數(shù)只需要將其添加為函數(shù)參數(shù)就可以聲明對(duì)另一類型的依賴。類型的依賴關(guān)系可以在添加類型之前或之后添加到圖中。

          提供 ClientService

          讓我們嘗試解決上一節(jié)中創(chuàng)建 ClientService 遇到的問(wèn)題。

          下面的代碼提供 ClientRepositoryImpl 作為 ClientRepository 實(shí)現(xiàn):

          type?ClientRepository?interface?{
          ???Do()
          }

          type?ClientRepositoryImpl?struct?{
          }

          func?(c?ClientRepositoryImpl)?Do()?{
          ???log.Println("Done")
          }
          var?C?*dig.Container

          func?main()?{
          ???C?=?dig.New()
          ???C.Provide(func()?ClientRepository?{
          ??????return?&ClientRepositoryImpl{}
          ???})
          }

          使用 dig 的好處是能自動(dòng)地為構(gòu)造函數(shù)提供所需要的依賴。在這個(gè)例子中,可能像下面這樣提供 ClientSevice:

          type?ClientService?struct?{
          ???clientRepository?ClientRepository
          }

          func?NewClientService(clientRepository?ClientRepository)?*ClientService?{
          ???return?&ClientService{clientRepository}
          }
          var?C?*dig.Container

          func?main()?{
          ???C?=?dig.New()
          ???C.Provide(func()?ClientRepository?{
          ??????return?&ClientRepositoryImpl{}
          ???})
          ???C.Provide(NewClientService)
          }

          從現(xiàn)在開(kāi)始,就可以在程序的任務(wù)位置,像下面這樣從 dig 容器中獲取 ClientService。

          var?clientService?*ClientService
          C.Invoke(func(s?*ClientService)?{
          ???clientService?=?s
          })

          使用 Dig 的好處

          • 不依賴具體的實(shí)現(xiàn),使得代碼更靈活且有利于單元測(cè)試;

          • 開(kāi)發(fā)人員無(wú)需費(fèi)心創(chuàng)建所有的依賴項(xiàng);

          • 所有的實(shí)現(xiàn)可以集中在一處位置進(jìn)行控制;

          總結(jié)

          遵循 SOLID 原則使得代碼更加靈活、易于測(cè)試和使用。依賴注入可以幫助你構(gòu)建對(duì)象,并可以減少冗余代碼。




          推薦閱讀



          學(xué)習(xí)交流 Go 語(yǔ)言,掃碼回復(fù)「進(jìn)群」即可


          站長(zhǎng) polarisxu

          自己的原創(chuàng)文章

          不限于 Go 技術(shù)

          職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)


          Go語(yǔ)言中文網(wǎng)

          每天為你

          分享 Go 知識(shí)

          Go愛(ài)好者值得關(guān)注


          瀏覽 63
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美亚洲成人网站 | 强开小嫩苞无码啪啪区 | 亚洲高清免费观看视频 | 久艹| 日韩aaaaaaa |