简体   繁体   中英

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?

What is a proper, working design for these desiderata?

Unity is component based and gets things complicated when you want to use it the way you in a normal C# application.

The simplest way is to use Composition. Make the Effect class it's own class that is not abstract. Just a normal class that inherits from MonoBehaviour . You can easily create new instance of it with AddComponent and get it with GetComponent . This script can also destroy itself directly after the timer is done counting without any problems.

Create a global variable in the DerivedEffect class to hold the instance of the Effect script that is created and this can be re-used over and over again until it becomes null which means that the script is destroyed. Note that there is no inheritance involved here and DerivedEffect script is only used as an example of the script that manages the Effect script.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM