Это правильное использование Dependency Injection? - PullRequest
3 голосов
/ 22 декабря 2011

У меня есть сервисный уровень, который извлекает DTO из хранилища.В зависимости от свойства в этом DTO мне нужно использовать одну из двух стратегий для выполнения расчетов в DTO.Я создал фабрику для возврата соответствующей стратегии, и я использую DI-контейнер ( Munq ) для создания экземпляра объекта.

public class CalculationFactory
{
    private readonly IDependencyResolver _resolver;
    public CalculationFactory(IDependencyResolver resolver)
    {
        ThrowIfNullArgument(resolver, "resolver", typeof(IDependencyResolver));
        _resolver = resolver;
    }

    public static ICalculation CreateCalculator(int serviceType)
    {
        switch (serviceType)
        {
            case 1: return _resolver.Resolve<ICalculation>("Type1");
            case 2: return _resolver.Resolve<ICalculation>("Type2");
            default: return _resolver.Resolve<ICalculation>("InvalidType");
        }
    }
}

Для этого необходимо передать преобразователь зависимостейкогда я создаю экземпляр фабрики, чтобы ее можно было использовать для разрешения / создания соответствующих вычислений.Это правильный подход?Если я хочу добавить новый тип расчета, мне нужно обновить заводской метод CreateCalculator и зарегистрировать новый тип.

Update (long) Я не получаю поддержкуБоюсь предложений.Я вернулся к своей копии DI Марка в .Net и, в частности, к главе 6 о рефакторинге.Итак, у меня есть класс MeterReadings , и мне нужно рассчитать заряд, используя один из двух расчетов на основе значения времени выполнения.Я добавляю абстрактную фабрику в смесь, но на моей бетонной фабрике мне все еще нужно новый до соответствующего расчета.Я чувствую, что здесь не хватает смысла:

public enum ServiceType
{
    Actuals = 1, CopyBlock,
}

public interface IChargeCalculator
{
    decimal CalculateCharge();
}

public interface IChargeCalculatorFactory
{
    IChargeCalculator CreateChargeCalculator(ServiceType serviceType);
}

public class MeterReading
{
    private readonly IChargeCalculatorFactory chargeCalculatorFactory;
    public MeterReading(IChargeCalculatorFactory chargeCalculatorFactory)
    {
        if (chargeCalculatorFactory == null)
            throw new ArgumentNullException("chargeCalculatorFactory");
        this.chargeCalculatorFactory = chargeCalculatorFactory;    
    }
}

public class ConcreteChargeCalculatorFactory : IChargeCalculatorFactory
{
    public IChargeCalculator CreateChargeCalculator(ServiceType serviceType)
    {
        switch (serviceType)
        {
            case ServiceType.Actuals : return new ActualsChargeCalculator();
            default: return new CopyBlockChargeCalculator();
        }
    }
}

Но в моем контейнере я могу зарегистрировать различные калькуляторы, и если я передаю в контейнер бетонный завод, я получаю что-то вроде следующего (не проверено) что откровенно выглядит довольно разумно для меня.Любые отзывы / разъяснения приветствуются.

Container.Register<IChargeCalculator>("Actuals",
                                      c => new ActualsChargeCalculator());
Container.Register<IChargeCalculator>("CopyBlock",
                                      c => new CopyBlockChargeCalculator());
...
public enum ServiceType
{
    Actuals = 1, CopyBlock,
}

public interface IChargeCalculator
{
    decimal CalculateCharge();
}

public class MeterReading
{
    private readonly IDependencyResolver chargeCalculatorFactory;
    private ServiceType serviceType;
    public MeterReading(IDependencyResolver chargeCalculatorFactory)
    {
        if (chargeCalculatorFactory == null)
            throw new ArgumentNullException("chargeCalculatorFactory");
        this.chargeCalculatorFactory = chargeCalculatorFactory;    
    }

    public decimal Charge
    {
        get
        {
            return chargeCalculatorFactory.Resolve<IChargeCalculator>(serviceType.ToString());
        }
    }
}

Ответы [ 2 ]

3 голосов
/ 22 декабря 2011

Да, я бы сказал, что вы делаете это правильно.

Несмотря на то, что вы пишете, что вам нужно "передать распознаватель зависимостей", есть причина, по которой у вас не может быть фабрикикласс вводится в класс где это нужно?Тогда зависимость factorys от решателя зависимостей должна быть разрешена самим решателем зависимостей (самому себе).

Я надеюсь, что предложение имело смысл.

Я пытался придумать "очиститель"Решение, но еще не нашли.Решение, подобное предложенному в вопросе (которое не совсем то же самое), ссылки на Dessus, безусловно, возможно, но я действительно вижу в этом просто перемещение того же кода в другое место.Remo также пишет, что это может быть сделано в фабричном классе вместо фабричного метода.

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

Кстати, я могу порекомендовать Ninject, это действительно хороший, чистыйдиатомовыйКроме того, в документации используются примеры ниндзя;)

0 голосов
/ 22 декабря 2011

Я полагаю, что на этот вопрос здесь был дан ответ, где предлагается использовать метаданные против своих привязок и создавать привязки для каждой реализации. Затем вы используете привязку для извлечения метаданных, чтобы выбрать, какую привязку использовать: Удалить условную привязку на основе значения свойства . Возможно, это может или не может быть возможно с Munq? Не уверен.

Человек (Ремо), который ответил на этот вопрос, является одним из архитекторов Nineject и очень хорошо осведомлен. Я считаю, что его ответ должен быть очень весомым. (Я основываюсь на этом как на подписчике на список рассылки для недобросовестных пользователей и на том, что он отвечает примерно на половину всех вопросов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...