控制和IoC容器的反转

时间:2018-11-29 17:04:35

标签: c# .net inversion-of-control ioc-container

我了解控制反转背后的整个概念,但是努力弄清楚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也不知道IWeaponITarget的具体类型。

所以这允许我做类似...

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容器如何工作的一些基本知识,但是我看过一些有关它们的视频(使用多个库),当我想要“某些”实现接口XX时,它们似乎都在说 ,请在您的容器中找到具体类型为YY的对象。如果您还没有,请创建一个,保存并发送回给我。

有人可以解释一下IoC容器的优点,给出它如何工作以及如何保留选择的真实示例(例如,不像上面那样将IWarrior限制为Samurai)吗?

0 个答案:

没有答案