Что такое хороший подход к обработке конкретных методов интерфейса?

#c# #design-patterns

#c# #шаблоны проектирования

Вопрос:

Допустим, у меня есть:

 public class Buff {
  ... code ...
}
 

Затем я реализую триггеры для своего баффа

 public interface IBuffOnActionTrigger {
   void OnPlayerAction(Player p);
}

public interface IBuffOnPlayerDie {
   void OnPlayerDie(Player p);
}
 

Итак, теперь я могу реализовать эти методы в буфере.

У меня есть следующий метод:

 public void TriggerBuffs<TriggerType>(Player p) {
    p.Buffs.Where(b => b is TriggerType).ForEach(b => b.<CALLMETHOD>);
}
 

В этом случае я использую случай переключения

 switch typeof(TriggerType):
   case IBuffOnPlayerDie:
      buff.OnPlayerDie(p);
   ... etc  
 

Но я искал способ сделать это более элегантно. Какой был бы хороший дизайн для этого?

Ответ №1:

Я думаю, что более простой способ запуска — просто использовать для этого разные методы

 public void TriggerActions(Player p)
{
    foreach (var buff in p.Buffs.OfType<IBuffOnActionTrigger>()) {
        buff.OnPlayerAction(p);
    }
}

public void TriggerPlayerDie(Player p)
{
    foreach (var buff in p.Buffs.OfType<IBuffOnPlayerDie>()) {
        buff.OnPlayerDie(p);
    }
}
 

OfType<T>() фильтрует буферы, реализующие T, и приводит их к T , упрощая вызов соответствующего метода.

Обратите внимание, что параметры универсального типа всегда разрешаются во время компиляции, т. Е. Они не обеспечивают динамического поведения во время выполнения. So void TriggerBuffs<TriggerType>(Player p) не позволяет динамически выбирать триггер.

Если вы хотите это сделать, используйте enum

 public enum TriggerType
{
    None,
    Action,
    PlayerDie
}
 

теперь вы можете динамически вызывать разные типы триггеров:

 public void Trigger(TriggerType triggerType, Player p)
{
    switch (triggerType) {
        case TriggerType.None:
            break;
        case TriggerType.Action:
            TriggerActions(p);
            break;
        case TriggerType.PlayerDie:
            TriggerPlayerDie(p);
            break;
        default:
            break;
    }
}