处理包含要求行为不同的同一类的派生的类

本文关键字:包含 一类 派生 处理 | 更新日期: 2023-09-27 18:09:56

我有一个Command类,当它被执行时,对一个IScriptable对象执行一个命令

[
    XmlInclude(typeof(CommandPositionSettings)),
]
public abstract class CommandSettings
{
    public List<Command> Parameters = new List<Command>(4);
    public abstract Command Load();
}
public abstract class Command
{
    public List<Command> Parameters = new List<Command>(4);
    public Command(CommandSettings settings) 
    {
        Parameters = settings.Parameters;
    }
    public abstract void Execute(IScriptable scriptableObject);
    public abstract int GetArgumentCount();
    public abstract CommandSettings Write();
}

对于某些命令,例如Position

,这很有效。
public class CommandPosition : Command
{
    public CommandPosition(CommandPositionSettings settings)
        :base(settings = settings == null ? new CommandPositionSettings() : settings)
    {
        if (settings == null)
        {
            settings = new CommandPositionSettings();
        }
    }
    public override void Execute(IScriptable scriptableObject)
    {
        Vector3 position = new Vector3();
        position.X = Parameters[0].Execute();
        position.Y = Parameters[1].Execute();
        position.Z = Parameters[2].Execute();
        scriptableObject.Position = position;
    }
    public override int GetArgumentCount()
    {
        return 3;
    }
    public override CommandSettings Write()
    {
        CommandPositionSettings settings = new CommandPositionSettings();
        settings.Parameters.AddRange(Parameters);
        return settings;
    }
}

,直到我尝试执行一个只需要返回值而不需要IScriptable的不同类型的命令。在上面的代码中,这将是获得位置的X, Y和Z值的地方。

在这一点上,将每个参数存储为浮点数是可以的,但有时我希望做一些比返回值更复杂的事情。例如,每次执行命令时在两个值之间随机化。

public class CommandRandom : Command
{
    public CommandRandom(CommandRandomSettings settings)
        : base(settings = settings == null ? new CommandRandomSettings() : settings)
    {
        if (settings == null)
        {
            settings = new CommandRandomSettings();
        }
    }
    public override float Execute()
    {
        return ToolBox.Random.NextFloat(Parameters[0], Parameters[1]);
    }
    public override int GetArgumentCount()
    {
        return 2;
    }
    public override CommandSettings Write()
    {
        CommandPositionSettings settings = new CommandPositionSettings();
        settings.Parameters.AddRange(Parameters);
        return settings;
    }
}

该命令只需要返回一个随机浮点数,而不直接影响IScriptable对象。

我目前从同一个类派生它们的另一个原因是,当解释命令行字符串时,它为 command (para0, para1…paraN)的每个匹配形式创建一个新的command。

一个命令也可以嵌套在另一个命令中。

So Command(para0, para1…paraN) where: para1 = Command(para0, para1…paraN)

那么我如何区分只需要返回值的嵌套命令和直接影响IScriptable对象本身的命令呢?

处理包含要求行为不同的同一类的派生的类

您可以使用泛型来解决这个问题,如:

public interface IScriptable
{
    Vector3 Position;
}
public abstract class CommandSettings<T>
{
    public List<Command<T>> Parameters = new List<Command<T>>(4);
    public abstract Command<T> Load();
}
public class CommandRandomSettings : CommandSettings<float>
{
    public Command<float> Load()
    {
        return null;
    }
}
public class CommandPositionSettings : CommandSettings<object>
{
    public Command<object> Load()
    {
        return null;
    }
}
public abstract class Command<T>
{
    public List<Command<T>> Parameters = new List<Command<T>>(4);
    public Command(CommandSettings<T> settings)
    {
        Parameters = settings.Parameters;
    }
    public abstract T Execute(IScriptable scriptableObject);
    public abstract int GetArgumentCount();
    public abstract CommandSettings<T> Write();
}
public class CommandRandom : Command<float>
{
    public CommandRandom(CommandRandomSettings settings)
        : base(settings = settings == null ? new CommandRandomSettings() : settings)
    {
        if (settings == null)
        {
            settings = new CommandRandomSettings();
        }
    }
    public override float Execute()
    {
        return 0.0f;
    }
    public override int GetArgumentCount()
    {
        return 2;
    }
    public override CommandSettings<float> Write()
    {
        CommandRandomSettings settings = new CommandRandomSettings();
        settings.Parameters.AddRange(Parameters);
        return settings;
    }
}
public class CommandPosition : Command<object>
{
    public CommandPosition(CommandPositionSettings settings)
        : base(settings = settings == null ? new CommandPositionSettings() : settings)
    {
        if (settings == null)
        {
            settings = new CommandPositionSettings();
        }
    }
    public override object Execute(IScriptable scriptableObject)
    {
        Vector3 position = new Vector3();
        position.X = Parameters[0].Execute();
        position.Y = Parameters[1].Execute();
        position.Z = Parameters[2].Execute();
        scriptableObject.Position = position;
    }
    public override int GetArgumentCount()
    {
        return 3;
    }
    public override CommandSettings<object> Write()
    {
        CommandPositionSettings settings = new CommandPositionSettings();
        settings.Parameters.AddRange(Parameters);
        return settings;
    }
}
不幸的是,在这种情况下,您不能传递void作为类型参数。在上面的示例中,我使用了object。Execute(IScriptable scriptableObject)方法可以简单地返回null