iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0
佛心分享-IT 人自學之術

靠近 ASP .NET Core 一點點系列 第 10

Day 10 DI:ASP.NET Core 中的核心設計模式,超重要!

  • 分享至 

  • xImage
  •  

前言
今天也到了這系列的 1/3 天數的分享課程了,也剛好要進入較為重要之二的重點, DI 注入個人認為它是 ASP .NET Core 中核心重點之一的設計模式,了解此觀念,會比只會用 ASP .NET Core 寫專案或是看專案內大家都這麼用,然後去使用,卻不清楚到底為何要用此種設計模式來的好!

前些年剛接觸 DI 時候(因為那時候專案又碰到 interface介面),我真的超級痛苦,因為它馬的超級抽象/images/emoticon/emoticon03.gif,而且通常抽象的知識,聽不到一半就會想睡覺甚至放棄學習它,然後那時我完全不懂為何要使用它XDD

所以我會盡量以白話一點方式去解說以及舉例程式碼,真心希望幫助到還有疑惑的大家!

分享主軸

  • 說明 DI 到底是什麼
  • 說明 DI 生命週期
  • 說明 DI 與以往的 new 差異

DI 何方神聖 ?

白話點,依賴注入(Dependency Injection, DI)是一種設計模式。它主要用於解決對象之間的依賴關係降低代碼的耦合度,提升可維護性和可測試性。

三個重點 :

  1. 它是一種設計模式
  2. 解決對象物件間的依賴 (以往 new 方式,容易導致高耦合度)
  3. 使專案程式碼在團隊間提升大家相互的好維護性與好測試性

補充 : 可能上網查會常看到 DI 達成控制反轉(IoC)的技術 (這邊不太多說明),總之白話一點就是,IoC 即一種概念,主要作用就是降低類別間的依賴,而這功用也就是上面講到的 : DI 可以做到的事情

所以 DI 注入是實現 IoC 這種概念的設計模式技術,內建於 ASP .NET Core 內。

DI 生命週期 ?

  • 依賴注入 ( DI ) 是一種設計模式,ASP.NET Core 中的依賴注入實現方式包括使用介面抽象類別、使用服務容器和使用建構函式注入等方法

  • 分三種 : ( 注入可以想成把實作類別 new 出一個實例 )

  1. 瞬時生命週期 (Transient) : 每次注入,都有一份
  2. 範圍生命週期 (Scoped) : 每一個request,只有一份
  3. 單一實體生命週期 (Singleton) : 整個應用程式從啟動到停止,就只有一份
builder.Services.AddScoped<要注入的服務>();
builder.Services.AddSingleton<要注入的服務>();
builder.Services.AddTransient<要注入的服務>();
  • DI 的概念就是 : 有一個 ServiceCollection,然後服務註冊進去,需要的時候拿出來用,然後管理它的生命週期,DI 只做這件事情

通常 DI 注入有幾種方式

  1. 建構式注入
  2. 方法注入

DI 與以往 new 差異 ?

舉一個超簡單範例,有一個 汽車類別引擎類別(汽車所需要的零件),需求是做出一台汽車可以啟動,如下範例 :

1. 直接使用 new

    //汽車
    public class Car
    {
        private Engine _engine;

        public Car()
        {
            _engine = new Engine(); 
        }

        public void Drive()
        {
            _engine.Start();
            Console.WriteLine("Car is driving.");
        }
    }
    
    //引擎1
    public class Engine
    {
        public void Start()
        {
            Console.WriteLine("Engine started.");
        }
    }
    
    //用到它 :
    Car car = new Car();
    car.Drive();

得出結果為
https://ithelp.ithome.com.tw/upload/images/20240923/20133954UjppHFFAZk.png

若今天要替換成引擎2,那等於上面 Car 類別內程式要調整,如下

//引擎2
public class AdvancedEngine
{
    public void Start()
    {
        Console.WriteLine("Advanced Engine started.");
    }
}

//汽車類別也得調整
public class Car
{
    private AdvancedEngine _engine;

    public Car()
    {
        _engine = new AdvancedEngine(); // 替換為新的實作
    }

    public void Drive()
    {
        _engine.Start();
        Console.WriteLine("Car is driving.");
    }
}

遇到的問題困擾

  • 多處修改:如果有多個類別依賴於 Engine,那麼每個類別都需要進行類似的修改,這會導致大量重複的工作和潛在的錯誤。
  • 緊耦合:Car 類別與 Engine 類別緊密耦合,這使得程式碼的可維護性和可測試性降低。每次需要替換實作時,都需要修改依賴的類別。
  • 難以測試:在單元測試中,我們無法輕易地替換 Engine 的實作為一個 mock 物件,這使得測試變得更加困難。(這邊不多做說明)

2. 使用 DI,這邊搭配介面做示範(Interface)

這邊使用介面去定義汽車需要用到的動作 : 啟動 方法

//定義引擎介面
public interface IEngine
{
    void Start();
}
//汽車類別
public class Car
{
   private readonly IEngine _engine;

    public Car(IEngine engine) //使用建構式注入方式
    {
        _engine = engine;
    }

    public void Drive()
    {
        _engine.Start();
        Console.WriteLine("Car is driving.");
    }
}
//引擎類別1
public class Engine : IEngine
{
    public void Start()
    {
        Console.WriteLine("Engine started.");
    }
}
//引擎類別2
public
class AdvancedEngine : IEngine
{
    public void Start()
    {
        Console.WriteLine("Advanced Engine started.");
    }
}
//在 program.cs內註冊服務
builder.services.AddScoped<IEngine, Engine>();
builder.Services.AddScoped<Car>();

使用引擎1,結果如下圖一
https://ithelp.ithome.com.tw/240923/20133954UjppHFFAZk.png

若今天要替換引擎2,此時只需要在註冊的地方更改程式,把需要用到的引擎實作註入進去介面即可,Car 類別完全不需要調整

builder.services.AddScoped<IEngine, AdvancedEngine>();

簡單統整今日重點

  • 了解依賴注入仍然可以讓我們的程式碼更加靈活、可測試和可維護,因此在 ASP.NET Core 推薦使用 DI 來管理相依性
  • 了解與 new 差異
  • 了解 DI 生命週期

今日結語
透過今日分享,相信可以大大理解 DI 生命週期到底是什麼以及與以往 new 差異,也更可以知道 ASP .NET Core 內建的這樣東西到底為什麼那麼好用? 為什麼需要用到它? 下次面試,也回答得出來,也真的讓自己理解。

真心希望有幫助到還有疑惑的人,明日繼續努力,謝謝。


上一篇
Day 9 Middleware : 自己動手做 Middleware 範例
下一篇
Day 11 組態 Configuration
系列文
靠近 ASP .NET Core 一點點13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言