如何将此服务定位器模式转换为真正的依赖注入模式

本文关键字:模式 依赖 注入 转换 服务 定位器 | 更新日期: 2023-09-27 18:25:12

我一分钟前问了一个更一般的问题:如何在应用程序中组织DI Framework的使用?,我得到的反馈是,我使用的是服务定位器模式,而不是马丁·福勒在这里指出的真正的DI:http://martinfowler.com/articles/injection.html

事实上,我前几天刚读过那篇文章,但显然还没有完全理解

假设我有以下代码:

interface ICardReader
{
    string GetInfo();
    void SetDebugMode(bool value);
    void Initialize(string accountToken);
    void ShowAmount(string amount);
    void Close();
    ICreditCardInfo GetCardInfo();
}
public class MagTekIPAD: ICardReader
{
    public ICreditCardInfo GetCardInfo()
    {
        var card = GetCardDataFromDevice();
        // apparently the following line is wrong?
        var ccInfo = Inject<ICreditCardInfo>.New(); 
        ccInfo.Track1 = MakeHex(card.EncTrack1);
        ccInfo.Track2 = MakeHex(card.EncTrack2);
        ccInfo.MagSignature = MakeHex(card.EncMP);
        ccInfo.MagSwipeKeySN = MakeHex(card.KSN);
        ccInfo.MagSignatureStatus = MakeHex(card.MPSts);
        ccInfo.MagDeviceSN = ipad.Serial;
        ccInfo.MSREncryptType = "MAGENSA_V5";
        return ccInfo;
    }
    // Other implementation details here ...
}

在这个例子中,我可以将依赖项注入构造函数中——我认为这是修复"这个"场景的正确方法。

但是,如果我真的需要创建一个未知数量的有问题的对象(或者我需要在类中动态创建依赖项是否有其他正当理由),该怎么办?

如何将此服务定位器模式转换为真正的依赖注入模式

这个例子给我的印象是,您试图使用IoC容器动态创建一个数据传输对象ICreditCardInfo。这样的对象不应该像服务一样具有任何真正的依赖关系。创建DTO的正确方法是使用new运算符:

return new CreditCardInfo(
        MakeHex(card.EncTrack1),
        MakeHex(card.EncTrack2),
        MakeHex(card.EncMP),
        MakeHex(card.KSN),
        MakeHex(card.MPSts),
        ipad.Serial,
        "MAGENSA_V5");

ICreditCardInfo对象的工厂注入MagTekIPAD 的构造函数

public class MagTekIPAD : ICardReader
{
  private readonly Func<ICreditCardInfo> factory;
  public MagTekIPAD(Func<ICreditCardInfo> factory)
  {
    this.factory = factory;
  }
  public ICreditCardInfo GetCardInfo()
  {
    var info = factory();
    // ...
    return info;
  }
}

如果几个容器知道如何创建T的实例,那么它们可以自动生成Func<T>委托,这样就不必定义工厂接口或抽象工厂类。

正如Fowler所指出的,服务定位器是更直接的方法,不太容易出错。

一些依赖注入框架要求您声明是在处理Singleton,还是它们可以有不同的生存期。