Я понимаю всю концепцию инверсии управления, но изо всех сил пытаюсь выяснить, где находится контейнер IoC и как он может помочь.
Вот пример.Допустим, у нас есть следующие интерфейсы ...
public interface IWarrior
{
string Name { get; }
IWeapon Weapon { get; }
void EquipWeapon(IWeapon weapon);
void Attack(ITarget target);
void DoVictoryDance();
}
public interface IWeapon
{
int AttackPower { get; }
}
public interface ITarget
{
int Health { get; }
int ArmorValue { get; }
int ReceiveAttack(int damage);
}
Базовый класс IWarrior ...
public abstract class BaseWarrior : IWarrior
{
private static readonly Random Random = new Random();
protected BaseWarrior(string name, IWeapon weapon)
{
Name = name;
Weapon = weapon;
}
public string Name { get; }
public IWeapon Weapon { get; private set; }
public virtual void Attack(ITarget target)
{
var attackValue = Random.Next(0, Weapon.AttackPower + 1);
var damageDone = target.ReceiveAttack(attackValue);
Console.WriteLine($"{Name} did {damageDone} to {target.GetType().Name}");
if (target.Health <= 0)
DoVictoryDance();
}
public virtual void EquipWeapon(IWeapon weapon)
{
Weapon = weapon;
Console.WriteLine($"{Name} equips {weapon.GetType().Name}");
}
public abstract void DoVictoryDance();
}
Типы бетонных воинов ...
public class Samurai : BaseWarrior
{
public Samurai(string name, IWeapon weapon) : base(name, weapon)
{
}
public override void DoVictoryDance()
{
Console.WriteLine($"{Name} dances on top of the corpses of his foes.");
}
}
public class ChuckNorris : BaseWarrior
{
public ChuckNorris() : base("Chuck Norris", null)
{
}
public override void Attack(ITarget target)
{
var targetName = target.GetType().Name;
Console.WriteLine($"Chuck Norris stares at {targetName}. {targetName} collapses on the floor, dead. {targetName} never saw Chuck Norris.");
DoVictoryDance();
}
public override void EquipWeapon(IWeapon weapon)
{
Console.WriteLine("Chuck Norris needs no weapons you fool!");
}
public override void DoVictoryDance()
{
Console.WriteLine("Chuck Norris doesn't dance. He stares at you until you do it for him.");
}
}
Следующее оружие ...
public class Sword : IWeapon
{
public int AttackPower => 10;
}
public class CrossBow : IWeapon
{
public int AttackPower => 15;
}
И, наконец, основной враг:
public class Bear : ITarget
{
public int Health { get; private set; } = 100;
public int ArmorValue => 2;
public int ReceiveAttack(int damage)
{
var damageTaken = damage - ArmorValue;
if (damageTaken > 0)
Health -= damageTaken;
return damageTaken;
}
}
Мне ясно, что такое инверсия контроля.Мой основной класс не должен знать конкретный тип IWarrior
, IWarrior
никогда не знает конкретный тип IWeapon
или ITarget
.
Так что это позволяет мне делать что-то вроде ...
ITarget target = new Bear();
IWarrior warrior = new ChuckNorris();
warrior.Attack(target);
или ...
ITarget target = new Bear()
IWarrior warrior = new Samurai("Ben", new Sword());
warrior.Attack(target);
И я вижу, как было бы проще иметь контейнер, который просто хранит мои объекты, чтобы я не "потерял их след" (я не хочу, чтобы вокруг было много мечей или оружия, например, это могут быть синглтоны).
Примеры, которые я видел для контейнеров IoC, показывают нечто похожее на это:
IocContainer container = new IocContainer();
container.Bind<IWarrior>().To<Samurai>();
container.Bind<IWeapon>().To<Sword>();
container.Bind<ITarget>().To<Bear>();
и затем делает что-то вроде ...
ITarget target = container.Get<ITarget>();
IWarrior warrior = container.Get<IWarrior>();
warrior.Attack(target);
Но теперь я в основном говорю, что мой IWarrior
всегда равен Samurai
, что мой IWeapon
всегда равен Sword
, и этомой ITarget
всегда Bear
.
Это не совсем то, что я хотел!Я хочу иметь возможность создавать различные типы IWarrior
с различными комбинациями IWeapon
и атаковать множество ITargets
!
Возможно, я неправильно понимаю что-то базовое о том, как работает контейнер IoC, но у меня естьЯ видел несколько видео о них (с использованием нескольких библиотек), и все они в основном говорят «1051», когда я хочу «что-то», реализующее интерфейс XX, найдите в своем контейнере объект конкретного типа YY.Если у вас его еще нет, создайте его, сохраните и отправьте мне.
Может кто-нибудь объяснить, в чем преимущества контейнера IoC, приведите реальные примеры его использования?работает и как можно сохранить выбор (не ограничивая IWarrior
до Samurai
, как указано выше, например)?