Как превратить этот шаблон Service Locator в настоящий шаблон внедрения зависимостей? - PullRequest
4 голосов
/ 21 февраля 2012

Минуту назад я задал более общий вопрос: Как организовать использование 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 ...
}

В этом примере я мог бы вставить зависимость в конструктор - и я думаю, что это правильный способ исправить «этот» сценарий.

Но что, если мне действительно нужно создать неизвестный номер рассматриваемого объекта (или есть какая-либо другая законная причина, по которой у меня возникнет необходимость создать зависимость на лету в классе)?

Ответы [ 3 ]

7 голосов
/ 21 февраля 2012

В этом примере создается впечатление, что вы пытаетесь создать объект передачи данных с именем ICreditCardInfo с использованием контейнера IoC. Такие объекты не должны иметь никаких реальных зависимостей, как сервис. Правильный способ создания DTO - использовать оператор new:

return new CreditCardInfo(
        MakeHex(card.EncTrack1),
        MakeHex(card.EncTrack2),
        MakeHex(card.EncMP),
        MakeHex(card.KSN),
        MakeHex(card.MPSts),
        ipad.Serial,
        "MAGENSA_V5");
3 голосов
/ 21 февраля 2012

Внедрить фабрику для 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;
  }
}

Несколько контейнеров могут автоматически генерировать Func<T> делегатов, если они знают, как создавать экземпляры T, поэтому вам не нужно определять фабричные интерфейсы или абстрактные фабричные классы.

0 голосов
/ 21 февраля 2012

Как отметил Фаулер, Service Locator является более прямым подходом и менее подвержен ошибкам.

В некоторых средах внедрения зависимостей требуется, чтобы вы указали, имеете ли вы дело с Singleton или они могут иметь различное время жизни .

...