Большинство каркасов DI позволяют вам внедрять примитивы в конструкторы, как показало Spinon .Когда это возможно, я пытаюсь реорганизовать свой код так, чтобы мне не требовались сложные конфигурации.Часто это делает мой код приложения наиболее понятным, с наименьшим количеством сюрпризов (небольшое количество WTF в минуту ;-)).Вы должны тщательно сбалансировать это, потому что иногда сложные конфигурации могут упростить код вашего приложения.
Вот несколько возможных предложений по рефакторингу:
1) Использовать фабрику:
Использование фабрики полезно, когда клиенты должны контролировать round
значение:
public interface IFootballLadderFactory
{
FootballLadder CreateNew(int round);
}
Таким образом, вы можете ввести IFootballLadderFactory
и разрешить клиентам звонить:
var ladder = this.footballLadderFactory.CreateNew(3);
2) Использовать свойство:
Вы можете удалить аргумент round
из конструктора и изменить его на свойство get / set.Это полезно, когда клиенты должны иметь возможность контролировать значение round
или при использовании фабрики:
public class FootballLadder
{
private IMatchRepository matchRepo;
public FootballLadder(IMatchRepository matchRepository)
{
}
public int Round { get; set; }
}
А реализация IFootballLadderFactory
, например, может выглядеть так:
public class CastleFootballLadderFactory : IFootballLadderFactory
{
public IWindsorContainer Container;
public FootballLadder CreateNew(int round)
{
var ladder = this.Container.Resolve<FootballLadder>();
ladder.Round = round;
return ladder;
}
}
Или клиент может установить свойство Round
:
public class Client
{
public Client(FootballLadder ladder)
{
ladder.Round = 3;
}
}
Пожалуйста, будьте осторожны с последним примером.Клиенту обычно не нужно заботиться о времени жизни зависимости.В этом случае мы меняем состояние внедренной зависимости.Это не позволяет нам изменить время жизни этой зависимости, потому что в этом случае состояние экземпляра ladder
может быть изменено из-под ног клиента.Кроме того, класс FootballLadder
должен выдавать InvalidOperationException
, когда Round
никогда не был установлен.Я думаю, что такая проверка хороша и чиста, но заставляет вас писать немного больше кода.
3) Внедрить IRoundProvider
в конструктор FootballLadder
:
Как писал Спинон, вы можете реализовать IRoundProvider
, но вместо того, чтобы использовать его в своей конфигурации, вы можете использовать его в качестве аргумента конструктора.
public class FootballLadder
{
private IMatchRepository matchRepo;
private int round;
public FootballLadder(IMatchRepository matchRepository,
IRoundProvider roundProvider)
{
this.round = roundProvider.GetRound();
}
}
4) Создать определенный подтипдля вашей конфигурации DI:
public class DIFootballLadder : FootballLadder
{
private const int Round = 3;
public DIFootballLadder(IMatchRepository matchRepository)
: base(matchRepository, Round)
{
}
}
Теперь вы можете зарегистрировать его следующим образом:
x.For<FootballLadder>().Use<DIFootballLadder>();
Недостатком этого является то, что у вас есть этот дополнительный код с собой в простой конфигурациикод.Кроме того, когда изменяются зависимости FootballLadder
, вам также необходимо изменить DIFootballLadder
.
Надеюсь, это поможет.