Ввод зависимостей - PullRequest
       17

Ввод зависимостей

1 голос
/ 18 декабря 2009

Если есть 3 интерфейса, подобные следующему

public interface IWeapon {
void Kill();
}

public interface ISword:IWeapon {
void Slice();
}

public interface IShuriken: IWeapon {
void Pierce();
}

public class Ninja {
public IWeapon Weapon {get;set;}
public void BrutalKill() {

/* warrior must pierce, pierce, pierce and then kill 


*/

}
public void HonorKill {
/* warrior must kill by one slice */
}
}

Для сценария, подобного этому, как бы вы подключили контейнер и как бы выглядело тело вашего метода для BrutalKill и HonorKill?

РЕДАКТИРОВАТЬ: Основываясь на комментариях, я думал о том, что ниндзя должен быть вооружен оружием ... если он хочет быть вооружен мечом или сюрикен ... должно быть решено позже ... не уверен, если я думаю правильно .. может быть, нам нужно разделить ниндзя с NinjaWithShuriken и NinjaWithSword

Ответы [ 4 ]

3 голосов
/ 18 декабря 2009

Не уверен, что это то, что вы ищете, но у меня было бы следующее:

// first some implementations
public class Sword : ISword {
    public void Kill() { // imp }
    public void Slice() { // imp }
}

public class Shuriken : IShuriken {
    public void Kill() { // imp }
    public void Pierce() { // imp }
}

// and I would change the Ninja class to
public class Ninja {
    public ISword Sword { get; private set; }
    public IShuriken Shuriken { get; private set; }

    public Ninja(ISword sword, IShuriken shuriken) {
        this.Sword = sword;
        this.Shuriken = shuriken;
    }

    public void BrutalKill() {
        Shuriken.Pierce();
        Shuriken.Pierce();
        Shuriken.Pierce();

        // either weapon can kill
        // so lets close the distance and use the sword
        Sword.Kill();
    }

    public void HonorKill {
        Sword.Slice();
    }
}

// creating the class
// where Ioc.Resolve is specific to the container implementation
var ninja = new Ninja(IoC.Resolve<ISword>(), IoC.Resolve<IShuriken>());

Обновление Мне нравится комментарий Фила Сэндлера, поэтому быстрое обновление, чтобы отразить это:

// a ninja interface
public interface INinja {
    void BrutalKill();
    void HonorKill();
}

// and then update the ninja class to
public Ninja : INinja {
    ...
}

// and have the ninja class created like this with the container
// resolving the dependencies:
var ninja = IoC.Resolve<INinja>();

Обновление Основываясь на обновлении исходного вопроса, я бы сказал:

public interface IWeapon {
    void Attack();
    void Kill();
}

public class Sword : ISword {
    public void Attack() {
        // implement as a slash
    }
    ...
}

public class Shuriken : IShuriken {
    public void Attack() {
        // implement as a pierce
    }
    ...
}

Идея в том, что нам все равно, как Меч и Сюрикен реализуют Атаку, до тех пор, пока ниндзя может использовать их для выполнения своих обязанностей при вызове. Убийство может быть осуществлено так, как того желает конкретный субъект, если работа будет выполнена в рамках указанного соглашения, в данном случае - Атакующим.

// create the specific ninja
var swordNinja = new Ninja(IoC.Resolve<ISword>());
var shurikenNinja = new Ninja(IoC.Resolve<IShuriken>());

// with the ninja class updated to only have an IWeapon 
// property that gets set in the constructor.
1 голос
/ 18 декабря 2009

Kill(), без параметров, похоже, что вы приказываете ниндзя покончить жизнь самоубийством. Я бы определил Ninja, чтобы действовать на других ниндзя:

public interface INinja
{
    void KillBrutally(INinja otherNinja);

    void KillHonorably(INinja otherNinja);
}

Затем поднимите уровень абстракции от оружия, чтобы убить ход:

public interface IKillMove
{
    void Kill(INinja ninja);
}

и ниндзя поддерживают типы убийств:

public sealed class Ninja : INinja
{
    private readonly IKillMove _brutalKillMove;
    private readonly IKillMove _honorableKillMove;

    public Ninja(IKillMove brutalKillMove, IKillMove honorableKillMove)
    {
        _brutalKillMove = brutalKillMove;
        _honorableKillMove = honorableKillMove;
    }

    #region INinja

    public void KillBrutally(INinja otherNinja)
    {
        _brutalKillMove.Kill(otherNinja);
    }

    public void KillHonorably(INinja otherNinja)
    {
        _honorableKillMove.Kill(otherNinja);
    }
    #endregion
}

Теперь мы можем беспокоиться об оружии:

public interface IWeapon
{
    void Attack(INinja ninja);

    void Finish(INinja ninja);
}

и убить ходы:

public sealed class MoveInKillMove : IKillMove
{
    private readonly IWeapon _shortRangeWeapon;
    private readonly IWeapon _longRangeWeapon;

    public MoveInKillMove(IWeapon shortRangeWeapon, IWeapon longRangeWeapon)
    {
        _shortRangeWeapon = shortRangeWeapon;
        _longRangeWeapon = longRangeWeapon;
    }

    #region IKillMove

    public void Kill(INinja ninja)
    {
        _longRangeWeapon.Attack(ninja);
        _longRangeWeapon.Attack(ninja);
        _longRangeWeapon.Attack(ninja);

        _shortRangeWeapon.Finish(ninja);
    }
    #endregion
}

public sealed class FinishingMove : IKillMove
{
    private readonly IWeapon _weapon;

    public FinishingMove(IWeapon weapon)
    {
        _weapon = weapon;
    }

    #region IKillMove

    public void Kill(INinja ninja)
    {
        _weapon.Finish(ninja);
    }
    #endregion
}

Вот пример подключения (переведите его в ваш контейнер IoC при необходимости):

var sword = new Sword();

var ninja = new Ninja(
    new MoveInKillMove(sword, new Shuriken()),
    new FinishingMove(sword));
1 голос
/ 18 декабря 2009

Если ваш ниндзя способен на BrutalKill и HonorableKill, он обязательно должен иметь ISword и IShuriken. Ниндзя зависит от них, поэтому мы объявляем их в ctor:

public class Ninja
{
    readonly IShuriken shuriken;
    readonly ISword sword;

    public Ninja(IShuriken sh, ISword sw)
    {
        shuriken = sh;
        sword = sw;
    }

    public void BrutalKill()
    {
        shuriken.Pierce();
        shuriken.Pierce();
        shuriken.Pierce();
        sword.Slice();
        shuriken.Kill();
    }

    public void HonorKill()
    {
        sword.Slice();
        sword.Kill();
    }
}

Вот наше оружие:

public interface IWeapon
{
    void Kill();
}

public interface IShuriken : IWeapon
{
    void Pierce();
}

public interface ISword : IWeapon
{
    void Slice();
}

Давайте получим пару реализаций этих зависимостей:

using System;

public class BronzeShuriken : IShuriken
{
    public void Pierce()
    {
        Console.WriteLine("Bronze shuriken pierce time now!");
    }

    public void Kill()
    {
        Console.WriteLine("Bronze shuriken kill!!!");
    }
}

public class RustySword : ISword
{
    public void Slice()
    {
        Console.WriteLine("Rusty sword slice time now!");
    }

    public void Kill()
    {
        Console.WriteLine("Rusty sword kill!!!");
    }
}

Наша конфигурация выглядит следующим образом:

using Ninject.Modules;

class DefaultModule : NinjectModule
{
    public override void Load()
    {
        Bind<IShuriken>().To<BronzeShuriken>();
        Bind<ISword>().To<RustySword>();
    }
}

И наша точка входа выглядит так:

    static void Main()
    {
        using (var kernel = new StandardKernel())
        {
            kernel.Load(new DefaultModule());

            kernel.Get<Ninja>().BrutalKill();
        }
    }
0 голосов
/ 18 декабря 2009

В единстве:

Container.RegisterType<INinja,Ninja>();
Container.RegisterType<ISword,Sword>();
Container.RegisterType<IShuriken,Shuriken>();

Предполагая, что у Ниндзя есть и Меч, и Сюрикен, поскольку только Меч может разрезать, и только Сюрикен может пробить.

Также у ниндзя есть конструктор, который принимает IShuriken и ISword в качестве аргументов.

И так, чтобы получить ниндзя,

var ninja= Container.Resolve<INinja>();
...