英文:
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<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
答案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 => _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<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 => _element;
public MagicEffect Effect { get; protected set; }
public void Init()
{
GetComponent<MagicEffectButton>().Init(_button, this.Effect);
GetComponent<MagicEffectView>().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() ;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论