mercredi 28 juin 2017

Proper way to create a static virtual factory method in C#

I'm implementing classes for Effects (something with a duration that applies a behavior in the FixedUpdate loop while it is active) in Unity3D.

I have a base abstract Effect class which has the behavior for keeping track of the duration, removing itself when the duration is up, and calling a protected abstract _doEffect function while its duration is up. In my derived classes, I override _doEffect to create Effects with different behaviors.

public abstract class Effect : MonoBehaviour
{
    public virtual float kDuration { get { return 1.0f; }}
    public static bool IsStackable { get { return false; }}
    private float _elapsed = 0.0f;

    protected virtual void Start()
    {
        _elapsed = kDuration;
    }

    protected virtual void FixedUpdate()
    {
        _elapsed -= Time.fixedDeltaTime;
        if(_elapsed <= 0) {
            Destroy(this);
        }

        _doEffect();
    }

    protected abstract void _doEffect();
}

Now, because you can't use constructors with Unity3D, I need a way to do the following for each derived Effect class when I'm applying a new Effect of that type to a game object:

1) If this type of effect is not stackable, then remove all other instances of this monobehaviour from the game object. 2) Create a new component of the effect type to the game object. 3) Do some initialization specific to that effect type.

For these requirements, I was imagining doing something like

public class DerivedEffect : Effect
{
    public override float kDuration { get {return 1.0f; }}
    public static bool IsStackable { get { return true; }}

    private int _derivedData;

    public static void Create(GameObject obj, int data)
    {
        DerivedEffect effect = DerivedEffect.CreateEffect(obj);
        effect._data = data;
    }

    protected override void _doEffect()
    {
        //Do some stuff
    }
}

and then in the base class putting

public static virtual Effect CreateEffect(GameObject obj)
{
    //T is somehow magically the type of the class you called this function on
    if(!T.IsStackable()) {
        //delete all components of type T on obj
    }
    T effect = obj.AddComponent<T>();
    return effect;
}

Obviously this isn't possible unless I do some weird stuff with generics and reflection that seems a bit extreme and probably not that right way to do things.

The crux is that I want a static function that does 1), 2), 3), and I want to share the code that does 1) and 2), and 1) depends on a bool which is different for every derived class.

What is a proper, working design for these desiderata?

Aucun commentaire:

Enregistrer un commentaire