【问题标题】:Handling a class that contains derivations of the same class which are required to behave differently处理包含同一类的派生的类,这些派生需要以不同的方式表现
【发布时间】:2013-04-12 18:44:13
【问题描述】:

我有一个 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();
}

这适用于某些命令,例如位置

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(para0, para1...paraN) 其中:para1 = Command(para0, para1...paraN)

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

【问题讨论】:

    标签: c# polymorphism derived-class


    【解决方案1】:

    您可以使用以下泛型类型来解决它:

    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 作为类型参数传递。在上面的示例中,我使用了对象。 Execute(IScriptable scriptableObject) 方法可以简单地返回 null

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-04
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 2014-12-01
      • 2013-11-19
      • 2022-01-02
      • 1970-01-01
      相关资源
      最近更新 更多