识别继承的类

huangapple go评论76阅读模式
英文:

Identifying inherited classes

问题

I have an abstract class (MagicEffect) that has a field with enum, also there are some inherited classes (like earth, air etc..), in their constructors they specify the enum value based on which they are.

The thing is that I need to initialize other class (doesn't matter what it is) with its element, but the only thing I know is enum value. I think that the best solution would be a static method that inheritors will override with their own values. But I don't know how to make it possible and the only solution I found is to make a switch like in example below.

public abstract class MagicEffect : Effect
{
    protected MagicEffect(DamageElements element,...) : base(element,...) { }

    public abstract static MagicEffect GetMagicEffect(DamageElements element) //the method I want
}

DamageElements - enum

public static MagicEffect GetMagicEffect(DamageElements element)
{
    switch(element) 
    {
        case DamageElements.Fire:
            return new Fire();

        case DamageElements.Water:
            return new Water();

        case...
    }
}
namespace Game.Controller
{
    public class MagicEffectInitializer : MonoBehaviour
    {
        [SerializeField] private List<ButtonController> _buttons;

        private void InitButtons()
        {
            foreach (var button in _buttons)
               button.Init(MagicEffect.GetMagicEffect(button.Element));
        }
    }
}
namespace Game.Controller
{
    [RequireComponent(typeof(MagicEffectButton))]
    [RequireComponent(typeof(MagicEffectView))]

    public sealed class ButtonController : MonoBehaviour
    {
        [SerializeField] private Image _selfImage;
        [SerializeField] private Sprite _spriteToSet;
        [SerializeField] private Button _button;
        [SerializeField] private DamageElements _element;

        public DamageElements Element => _element;

        public void Init(MagicEffect magicEffect)
        {
            GetComponent<MagicEffectButton>().Init(_button, magicEffect);
            GetComponent<MagicEffectView>().Init(_selfImage, _spriteToSet);
        }
    }
}

My question: is there a better solution without that terrible switch?

PS: Sorry for that title, I don't really know how to short this.

英文:

I have an abstract class (MagicEffect) that has a field with enum, also there are some inherited classes (like earth, air etc..), in their constructors they specify the enum value based on which they are.

The thing is that I need to initialize other class (doesn't matter what it is) with its element, but the only thing I know is enum value. I think that the best solution would be a static method that inheritors will override with their own values. But I don't know how to make it possible and the only solution I found is to make a switch like in example below.

public abstract class MagicEffect : Effect
{
        protected MagicEffect(DamageElements element,...) : base(element,...) { }

        public abstract static MagicEffect GetMagicEffect(DamageElements element) //the method I want
}

DamageElements - enum

public static MagicEffect GetMagicEffect(DamageElements element)
{
    switch(element) 
    {
        case DamageElements.Fire:
            return new Fire();

        case DamageElements.Water:
            return new Water();

        case...
    }
}
namespace Game.Controller
{
    public class MagicEffectInitializer : MonoBehaviour
    {
        [SerializeField] private List&lt;ButtonController&gt; _buttons;

        private void InitButtons()
        {
            foreach (var button in _buttons)
               button.Init(MagicEffect.GetMagicEffect(button.Element));
        }
    }
}
namespace Game.Controller
{
    [RequireComponent(typeof(MagicEffectButton))]
    [RequireComponent(typeof(MagicEffectView))]

    public sealed class ButtonController : MonoBehaviour
    {
        [SerializeField] private Image _selfImage;
        [SerializeField] private Sprite _spriteToSet;
        [SerializeField] private Button _button;
        [SerializeField] private DamageElements _element;

        public DamageElements Element =&gt; _element;

        public void Init(MagicEffect magicEffect)
        {
            GetComponent&lt;MagicEffectButton&gt;().Init(_button, magicEffect);
            GetComponent&lt;MagicEffectView&gt;().Init(_selfImage, _spriteToSet);
        }
    }
}

My question: is there a better solution without that terrible switch?

PS: Sorry for that title, I don't really know how to short this

答案1

得分: 1

你必须正确地反映出关系。要么向类型添加一个属性,允许配置实例以具有特定行为(例如一个 MagicEffect 属性),要么创建一个专门的特化类型,实现特殊行为(无需实例配置)。

以下示例定义了一个专门的类型来封装特定行为。FireButtonController 将提供所需的 Fire 效果(类型为 MagicEffect)。现在,您无需配置实例,而是创建正确的专用实例:

namespace Game.Controller
{    
    public class MagicEffectInitializer : MonoBehaviour
    {
      [SerializeField] private List<ButtonController> _buttons;

      private void InitButtons()
      {
          foreach (var button in _buttons)
             button.Init();
      }
    }
}
namespace Game.Controller
{
    public sealed class FireButtonController : ButtonController
    {
        public FireButtonController()
        {
            this.Effect = new Fire();
        }
    }
}
namespace Game.Controller
{
    [RequireComponent(typeof(MagicEffectButton))]
    [RequireComponent(typeof(MagicEffectView))]

    public sealed class ButtonController : MonoBehaviour
    {
        [SerializeField] private Image _selfImage;
        [SerializeField] private Sprite _spriteToSet;
        [SerializeField] private Button _button;

        //[SerializeField] private DamageElements _element;
        //public DamageElements Element =&gt; _element;

        public MagicEffect Effect { get; protected set; }

        public void Init()
        {
            GetComponent<MagicEffectButton>().Init(_button, this.Effect);
            GetComponent<MagicEffectView>().Init(_selfImage, _spriteToSet);
        }
    }
}

// 不再通过分配例如 `DamageElements.Fire` 效果标识符来配置 ButtonController,
// 而是直接创建一个使用所需效果的专用实例。
// 创建 ButtonController 的上下文显然具有所有所需的知识。
var buttonController = new FireButtonController() ;
英文:

You must reflect the relationship properly. Either add an attribute to the type that allows to configure the instance to have a particular behavior (for example a MagicEffect property) or create a dedicated specialized type that implements the special behavior (no instance configuration required).

The following example defines a specialized type to encapsulate a particular behavior. A FireButtonController will provide the required Fire effect (of type MagicEffect). Instead of configuring the instance you now create the correct specialized instance:

namespace Game.Controller
{    
    public class MagicEffectInitializer : MonoBehaviour
    {
      [SerializeField] private List&lt;ButtonController&gt; _buttons;

      private void InitButtons()
      {
          foreach (var button in _buttons)
             button.Init();
      }
    }
}
namespace Game.Controller
{
    public sealed class FireButtonController : ButtonController
    {
        public FireButtonController()
        {
            this.Effect = new Fire();
        }
    }
}
namespace Game.Controller
{
    [RequireComponent(typeof(MagicEffectButton))]
    [RequireComponent(typeof(MagicEffectView))]

    public sealed class ButtonController : MonoBehaviour
    {
        [SerializeField] private Image _selfImage;
        [SerializeField] private Sprite _spriteToSet;
        [SerializeField] private Button _button;

        //[SerializeField] private DamageElements _element;
        //public DamageElements Element =&gt; _element;

        public MagicEffect Effect { get; protected set; }

        public void Init()
        {
            GetComponent&lt;MagicEffectButton&gt;().Init(_button, this.Effect);
            GetComponent&lt;MagicEffectView&gt;().Init(_selfImage, _spriteToSet);
        }
    }
}

// Instead of configuring the ButtonController 
// by assigning a e.g. `DamageElements.Fire` effect identifier
// you directly create a specialed instance that uses the desired effect.
// The context that creates the ButtonController obviously has all the required knowledge.
var buttonController = new FireButtonController() ;

huangapple
  • 本文由 发表于 2023年6月26日 04:09:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76552223.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定