Back

Dependency Injection 與工廠模式的結合(2)

前言

前面一篇提到了 DI 的概念,透過 DI 的方式來實現解耦合,而這篇則是要來講 DI 的一些進階應用了

工廠模式

先說明工廠模式的運作方式,直接看Code比較快

資料來源

// Empty vocabulary of actual object
public interface IPerson
{
    string GetName();
}

public class Villager : IPerson
{
    public string GetName()
    {
        return "Village Person";
    }
}

public class CityPerson : IPerson
{
    public string GetName()
    {
        return "City Person";
    }
}

public enum PersonType
{
    Rural,
    Urban
}

/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
    public IPerson GetPerson(PersonType type)
    {
        switch (type)
        {
            case PersonType.Rural:
                return new Villager();
            case PersonType.Urban:
                return new CityPerson();
            default:
                throw new NotSupportedException();
        }
    }
}

這個案例裡面有兩個角色,分別是

  • Rural
  • Urban

而我只要告訴工廠,現在是哪種人,工廠就會建立相對應的實例會來給我.

而我也不用關心他的細節是什麼,只要關心他有提供什麼方法即可(Interface)

封裝的概念:隱藏細節,注重提供什麼

DI工廠

其實就只是將工廠做成Interface 放進 DIPool中

PersonModel

namespace DelegateFactory.Model
{

  public interface IPerson
  {
    string GetName();
  }

  public class Villager : IPerson
  {
    public string GetName()
    {
      return "Village Person";
    }
  }

  public class CityPerson : IPerson
  {
    public string GetName()
    {
      return "City Person";
    }
  }

  public enum PersonType
  {
    Rural,
    Urban
  }
}

FactoryClass

namespace DelegateFactory.Factory
{
  public interface IFactory
  {
    IPerson GetPerson(PersonType type);
  }

  public class PersonFactory : IFactory
  {
    public IPerson GetPerson(PersonType type)
    {
      switch (type)
      {
        case PersonType.Rural:
          return new Villager();
        case PersonType.Urban:
          return new CityPerson();
        default:
          throw new NotSupportedException();
      }
    }
  }
}

Controller

namespace DelegateFactory.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly ILogger<WeatherForecastController> _logger;
    private readonly IFactory _factory;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, IFactory factory)
    {
        _logger = logger;
        _factory = factory;
    }

    [HttpGet("name/{role}")]
    public ActionResult<string> GetName(string role)
    {
        bool isEnumRole =Enum.TryParse(role,out PersonType personType);
        if(isEnumRole){
            string name = this._factory.GetPerson(personType).GetName();
            return Ok(name);
        }else{
            return BadRequest("Unknow Role");
        }
    }
}

這樣起起來就有一個很基本的工廠模式,透過傳進來的 Role 來決定實際上拿到哪個實例並回傳

結論

透過這樣的方式可以大幅的增加擴充的彈性,但相對的因為抽象,也會導致使用上會變有些不方便,例如:Debug,Code Review 等會變成有些困難

因此是否要採用這種方式還需要特別根據團隊能力或商務邏輯來決定是否要採用

Sample Code

https://github.com/tonny0531/DIFactory