2011-02-28 69 views
0

我正在编写自己的'魔方'应用程序。主类Cube具有18点旋转的方法:LinkedList撤销/重做功能<Action>实施

  • RotateAxisXClockWise,RotateAxisXAntiClockWise
  • RotateAxisYClockWise,RotateAxisYAntiClockWise
  • RotateAxisZClockWise,RotateAxisZAntiClockWise

  • RotateUpperFaceClockWise,RotateUpperFaceAntiClockWise

  • RotateFrontFaceClockWise,RotateFrontFaceAntiClockWise
  • RotateRightFaceClockWise,RotateRightFaceAntiClockWise
  • RotateBackFaceClockWise,RotateBackFAceAntiClockWise
  • RotateLeftFaceClockWise,RotateLeftFaceAntiClockWise
  • RotateDownFaceClockWise,RotateDownFaceAntiClockWise

是,它们可以以对被接合与一参数方向(例如RotateFrontFace(Direction direction))但现在这个似乎适当。

我想实现撤销/重做功能,因为所有方法都有相同的签名(没有输入参数,无效返回类型),他们可以保存在LinkedList数据结构中。所以每次调用其中一种旋转方法时,它都会添加到链接列表中。

如果我们从LinkedList的开始处开始(尽管还没有尝试过)并且朝向结尾前进,那么这将工作得很好,因此每次轮换将按照首先执行的方式执行。

但是如何撤消?如果我从头到尾遍历列表,则应该调用相反的方法(例如,应该调用RotateFrontFaceClockWise,RotateFrontFaceAntiClockWise)。任何想法如何实现这一点?优雅? :)

回答

1

我不会使用委托引用作为模型旋转的方法,如果其中一个主要目的是能够执行重做/撤消。我会考虑为每次轮换创建一个数据模型,并存储这些轮换步骤的列表。然后每个步骤都可以拥有它自己的关联重做/撤销委托,它允许有人遍历列表(从任一端)来了解发生了什么操作,并重复或反转它们。

面向数据的方法来模拟这种转换的另一个好处是,它可能会减少RotateXXX()方法的类似(但略有不同)版本的数量。

编辑:解决您关于这种解决方案可能需要什么形状的问题。

最简单的做法可能是将代表每对旋转/非旋转操作的Tuple<Action,Action>存储为配对代表。但是,我会考虑使用描述旋转操作的显式数据结构,也许最终会包含诸如描述性名称,方向/面部属性等内容。我还会更改RotateXXX方法,以便它们是Cube的静态方法,并接受多维数据集的实例作为参数。这将允许将外部的旋转操作建模为Cube的实例。

public sealed class Rotation 
{ 
    private readonly Action<Cube> _RotateAction; 
    private readonly Action<Cube> _UnrotateAction; // used for undo or backtracking 

    private Rotation(Action<Cube> rotateAction, Action<Cube> unrotateAction) 
    { 
     _RotateAction = rotateAction; 
     _UnrotateAction = unrotateAction; 
    } 

    public void Rotate(Cube cube) { _RotateAction(cube); } 

    public void Unrotate(Cube cube) { _Unrotate(cube); } 

    public static readonly RotateFrontFaceClockswise = 
     new Rotation(Cube.RotateFrontFaceClockwise 
         Cube.RotateFrontFaceCounterClockwise); 

    public static readonly RotateFrontFaceCounterClockwise = 
     new Rotation(Cube.RotateFrontFaceCounterClockwise, 
         Cube.RotateFrontFaceClockwise); 

    public static readonly RotateLeftFaceClockwise = 
     new Rotation(Cube.RotateLeftFaceClockwise, 
         Cube.RotateLeftFaceCounterClockwise); 

    public static readonly RotateLeftFaceCounterClockwise = 
     new Rotation(Cube.RotateLeftFaceCounterClockwise, 
         Cube.RotateLeftFaceClockwise); 
    // etc.. 
} 

// now we can keep track of the state changes of a cube using: 
List<Rotation> cubeRotations = new List<Rotation>(); 
cubeRotations.Add(Rotation.RotateFrontFaceCounterClockwise); 
cubeRotations.Add(Rotation.RotateBackFaceClockwise); 
cubeRotations.Add(Rotation.RotateLeftFaceCounterClockwise); 

// to apply the rotations to a cube, you simple walk through the data structure 
// calling the Rotate() method on each: 
Cube someCube = new Cube(...) 
foreach(Rotation r in cubeRotations) 
{ 
    r.Rotate(someCube); 
} 

// to undo these rotations you can walk the like in reverse: 
foreach(Rotation r in cubeRotations.Reverse()) 
{ 
    r.Unrotate(someCube); 
} 
+0

这个数据模型是怎么样的?可以举个例子吗? – sventevit 2011-03-01 19:39:21

1

我知道你想避免你的参数化方法,但你可能最好关闭奉行类似的规定:

enum Face 
{ 
    Top, 
    Bottom, 
    Left, 
    Right, 
    Front, 
    Back 
} 

enum Direction 
{ 
    Clockwise, 
    CounterClockwise 
} 

struct Rotation 
{ 
    public Face Face; 
    public Direction Direction; 
} 

LinkedList<Rotation> actions; 

你可以选择是否将推动直接或反转动作到列表中,但是一旦以这种方式存储动作,就很容易编写一些快速切换语句,以便在从列表中移除时反转该动作。

在附注中,考虑将StackList替换为Stack,它将服务于您,并且完全适合您的目的。

编辑:

注意到,我没有为我的枚举轴旋转的支持,但我敢肯定,你可以将它们添加在票面枚举的附加条目(虽然你可能想将其重命名在这一点上)

0

假设你真的要坚持你的模型......

你可以通过在列表中执行的方法,每名进入尝试,然后与反思,通过重复调用零件柜在名单上。这假定您的方法将具有匹配的名称(如您所建议的)。

您还可以创建一个HybridDictionary,将方法名称用作计数器方法的ID和地址作为值。所以当你迭代列表时,你可以让委托处理给定值的方法。

+0

我个人不建议追求这个解决方案,无论是缓存代表或直接反射调用。反射是一个有用的工具,但应该在有实际需要时使用,而不是像这样的兴奋 – LorenVS 2011-02-28 20:55:23

+0

我同意,我认为他应该采取其他方法。除了反思真的很重要的资源。但是我只是在发表意见,这取决于他的决定......但是,这是给出的问题,虽然...... – PedroC88 2011-02-28 20:57:47

1

18个方法似乎有很多需要跟上,特别是当您考虑实现撤消/重做功能时。你有没有考虑过使用一种更通用的方法?如果你这样做了,你可以以非常一致的方式存储传递给该方法的内容,并轻松执行相反的操作。相反的行为可以从字典中查找。