Какой тип интерфейса подходит для реализации стратегии с другой сигнатурой? - PullRequest
1 голос
/ 20 февраля 2020

рассмотрите следующий код игры:

public class Player : MonoBehaviour {
    public void UseItem(Item item) {
        item.Use(this);
    }
    public void GetDrunk() {}
}

public class Item {
    public WhatInterface[] itemUsages;

    public void Use(Player player) {
        foreach(var usage in itemUsages) {
            usage.Execute(new ItemUsageArgs {itemUser = player, itemUsed = this})
        }
    }
}

public class GameManager : MonoBehaviour {

    public Player mainCharacter;
    public Item beer = new Item {itemUsages = new [] {
        new TestConsole(),
        new DamageFromItem (),
        new DrunkFromITem ()
    }}

    private void Start() {
        mainCharacter.Use(beer);
    }
}

public class TestConsole : WhatInterface {
    public void Execute(BaseArgs args) {
        Debug.Log("function call executed");
    }
}

public class DamageFromItem : WhatInterface {
    public void Execute(ItemUsageArgs args) {
        Debug.Log(args.itemUser + " take damage from " + args.itemUsed);
    }
}

public class DrunkFromITem : WhatInterface {
    public void Execute(ItemUsageArgs args) {
        args.itemUser.GetDrunk();
    }
}

public class BaseArgs {}

public class ItemUsageArgs : BaseArgs {
   public Player itemUser;
   public Item itemUsed;
}

так как создать код типа интерфейса, который подходит для itemUsages?

Или я ошибочно создаю дизайн для этого контекста?

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

То, что я пробовал, создавая интерфейс IItemUsage:

public interface IItemUsage {
    void Execute(ItemUsageArgs args);
    // but then anything that needs to implement this interface must use this method, even though it only needs BaseArgs.
    // TestConsole class must conform to Execute(ItemUsageArgs) signature..
}

public class TestConsole : IItemUsage {
    public void Execute(BaseArgs args) {
        Debug.Log("function call executed");
    }
    // this won't compile
}

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Предполагая, что это весь ваш код, вы можете сделать IItemUsage generi c и контраварант для параметра generi c.

public interface IItemUsage<in T> where T: BaseArgs {
    void Execute(T args);
}

Имеете TestConsole реализовать IItemUsage<BaseArgs>, а другие два класса - IItemUsage<ItemUsageArgs>.

Теперь вы можете поместить экземпляры всех трех классов в IItemUsage<ItemUsageArgs>[]:

IItemUsage<ItemUsageArgs>[] arr = new IItemUsage<ItemUsageArgs>[] { 
    new TestConsole(), new DamageFromItem(), new DrunkFromITem()
};
0 голосов
/ 20 февраля 2020

Если вы хотите реализовать интерфейс с некоторым методом, который имеет входные аргументы, которые могут быть разных типов, вы должны определить базовый класс аргумента или использовать вместо него параметр интерфейса.

Например:

public interface IItemUsage
{
    void Execute(IItemUsageArgs args);
}
public interface IItemUsageArgs
{
    //place public part of all ItemUsageArgs
}

public class ItemUsageArgs1 : IItemUsageArgs
{

}

public class ItemUsageArgs2 : IItemUsageArgs
{

}
public class ItemUsage1 :IItemUsage
{
    public void Execute(ItemUsageArgs1 args)
    {
        //do you need
    }
    void IItemUsage.Execute(IItemUsageArgs args)
    {
        Execute(args as ItemUsageArgs1);
    }
}

public class ItemUsage2 : IItemUsage
{
    public void Execute(ItemUsageArgs2 args)
    {
        //do you need
    }
    void IItemUsage.Execute(IItemUsageArgs args)
    {
        Execute(args as ItemUsageArgs2);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...