允许用户安排方法

时间:2012-10-07 14:34:24

标签: c# winforms events delegates

假设我有一个Player课程。它有一个Move方法,它接受一个方向参数,一个ChangePosition方法,它接受两个整数,一个Disappear void方法,以及其他方法。

我想允许用户(可能使用listbox)能够将一些方法添加到Player对象的行为中。例如,他们可以选择让它向右移动然后向下移动然后消失。然后,他们选择的方法将被添加到事件中,以便在该事件发生时,他们选择的方法将执行。

以前有人做过这样的事吗?做这个的最好方式是什么? (我13岁,我对设计模式知之甚少)

3 个答案:

答案 0 :(得分:2)

首先,您应该将所有游戏逻辑放入一个Engine项目中,使用Engine类,它只负责(处理所有游戏的逻辑并与UI和Framework进行通信[和更低层,如果有的话]是任何])。

其次,您可以拥有一个EngineAction类,它具有枚举EngineActionType(Move,ChangePos,Disappear,...)和其他属性。一般的想法是:

有一个枚举来保存类型:

public enum EngineActionType
{
    Move,
    ChangePos,
    Disappear,
    ...
}

创建一个抽象类,以逻辑方式对所有引擎操作类进行分组,并使用公共Type属性添加它们:

public abstract class EngineAction
{
    public readonly EngineActionType Type;

    protected EngineAction(EngineActionType type)
    {
        this.Type = type;
    }
}

为每个引擎操作创建一个类,该操作将所有必需参数保存为属性。它应该派生自EngineAction并将适当的EngineActionType发送到基础构造函数:

public class EngineActionMove : EngineAction
{
    public int XDelta;
    public int YDelta;

    public EngineActionMove() : base(EngineActionType.Move)
    {
    }
}

public class EngineActionChangePos : EngineAction
{
    ...
}

...

毕竟,你可以把这些对象放在一个列表中,就像用户订购一样,然后迭代它,根据它们的类型逐个执行:

foreach (EngineAction action in actionsToDo)
{
    switch (action.Type)
    {
        case EngineActionType.Move:
            EngineActionMove mvAction = (EngineActionMove)action;

            // Example:
            player.Position = player.Position.Offset(mvAction.XDelta,
                                                     mvAction.YDelta);
            break;
        case EngineActionType.ChangePos:
            EngineActionChangePos cpAction = (EngineActionChangePos)action;

            // Example:
            player.Position = new Point(cpAction.X, cpAction.Y);
            break;
        case EngineActionType.Disappear:
            // Just make the player disappear,
            // because the operation needs no parameters
            player.Disappear();
            break;
        case ...:
        default:
            // maybe throw an error here, to find errors during development
            // it helps you find non-handled action types
    }
}

进一步提示:UI中的逻辑最少,越好。总是

编辑:Charleh的好主意:

public interface IEngineAction
{
    void Do(Player target);
}

public class EngineActionMove : IEngineAction
{
    public int XDelta;
    public int XDelta;

    public void Do(Player target)
    {
        // Example
        target.Position = ...
    }
}

public class EngineActionDisappear : IEngineAction
{
    public void Do(Player target)
    {
        // Example
        target.Visible = false;
    }
}

...

添加到列表示例:

var actionsToDo = new List<IEngineAction>();

actionsToDo.Add(new EngineActionDisappear());
actionsToDo.Add(new EngineActionMove { XDelta = 10, YDelta = 20 });

迭代:

foreach (IEngineAction action in actionsToDo)
{
    action.Do(player);
}

答案 1 :(得分:2)

另一种选择是使用Action泛型并只添加您想要的方法,然后您可以在任何特定的玩家对象上调用这些操作。

这只是其他人提出的界面设计理念的替代方案,但你的风格可能更喜欢这种方法。

Action<Player> playerActions = p => {}; //Do Nothing
playerActions += p => { p.Move(3); }; //Move
playerActions += p => { p.ChangePosition(1, 1); }; //Change position
playerActions += p => { p.Disappear(); }; //Disappear

//Invoke Actions
Player player = new Player();
playerActions(player);

//Invoke on another object as well
Player player2 = new Player();
playerActions(player2);

答案 2 :(得分:1)

有很多方法可以做到这一点。一种方法是使用工厂模式和策略模式。

public static class PlayerBuilder
{
    public static Player BuildPlayer(BuildDefinition definition)
    {
        //logic in here to build a player -- pseudo-return value below as an example
        var strategy = new PlayerMovementStrategy();
        return new Player(strategy);
    }
}

您的BuildDefinition课程可以根据您的用户选择进行构建。听起来他们不能只添加任何内容,而是从预定义选项列表中进行选择。根据您的UI选择创建适当的策略。

abstract class MovementStrategy
{
    public abstract void Move();
    public abstract void ChangePosition(Direction d);    
}
class PlayerMovementStrategy
{
    public override void Move()
    {
        //move
    }
    public override void ChangePosition(Direction d)
    {
        //change position
    }
}
abstract class VisibilityStrategy
{
    public abstract void Disappear();
}
class PlayerVisibilityStrategy
{
    public void Disappear()
    {
        //poof 
    }
}

class Player
{
     private readonly PlayerMovementStrategy movement;
     private readonly PlayerVisibilityStrategy visibility;

     public Player(PlayerMovementStrategy movement, PlayerVisibilityStrategy visibility)
     {
         this.movement = movement;
         this.visibility = visibility;
     }

     public void Disappear()
     {
         visibility.Disappear();
     }         
     public void Move(Direction d)
     {
         movement.Move(d);
     }
}