在这个简单的例子中如何思考“告诉,不要问”?

时间:2010-02-07 01:12:42

标签: actionscript-3 oop tell-dont-ask

在下面的简单场景中,您如何遵守“告诉,不要问”原则(以下简称“原则”)?在俄罗斯方块游戏中,我有与以下示例相关的Board,BlockGrid和Piece类:

public class Board
{
    private var fallingPiece:Piece;
    private var blockGrid:BlockGrid;
    ...
    public function moveFallingPiece(xDirection:int, yDirection:int):void
    {
        blockGrid.movePiece(fallingPiece, xDirection, yDirection);
    }
} 

一旦fallPiece被放置在BlockGrid的底行,它就不再是“fallingPiece”了。我是对的,我没有违反以下原则吗?

if(blockGrid.getPiecePosition(piece).y == 0)
{
    fallingPiece = null;
}

但这与我真的不同,我认为这显然违反了原则吗?

public function moveFallingPiece(xDirection:int, yDirection:int):void
{
    if(blockGrid.getPiecePosition(piece).y > 0)
    {
        blockGrid.movePiece(fallingPiece, xDirection, yDirection);
    }
    else
    {
        fallingPiece = null;
    }
}

我并没有假设我已经以正确的方式设计了这些类关系来处理这个原则。如果这是我缺少的,请就替代设计提出建议。


编辑,提议的解决方案:

我选择了通过事件提出“命令反馈”的答案。 Board告诉BlockGrid移动一块。 BlockGrid的movePiece方法根据结果调度MOVED_TO或MOVE_FAILED事件,Board可以监听并使用它来确定一块是否已经停止下降。请不要犹豫,就此解决方案提供反馈。

public class Board
{
    ...
    public function Board()
    {
        ...
        blockGrid.addEventListener(PieceMoveEvent.MOVE_FAILED, onPieceMoveFailed);
        ...
    }

    public function moveFallingPiece(xDirection:int, yDirection:int):void
    {
            blockGrid.movePiece(fallingPiece, xDirection, yDirection);
    }

    public function onPieceMoveFailed(event:MovePieceEvent):void
    {
        if(event.instance == currentlyFallingPiece && event.fromPosition.y != event.toPosition.y)
        {
             currentlyFallingPiece = null;
        }
    }

4 个答案:

答案 0 :(得分:1)

我认为,为了更好地遵循Tell,Do not Ask原则,当fallPiece达到它的休息点时,你应该让blockGrid通知你的Board class。在上面的两个场景中,您要求blockGrid是否该块的position.y == 0以确定fallingPiece是否应为null。相反,您希望blockGrid告诉Board类fallPiece.y已经达到0。

答案 1 :(得分:1)

您正在寻找的是事件驱动编程。您需要一个名为.event()的方法的Listener接口和一个表示事件的Event接口。对象将向其他对象(回调)注册到Listener接口。

当你创建一个棋子和棋盘时,他们应该实现监听器界面。然后你可以用registerListener(board)设置Board;然后当在Piece内部发生事情时,它将循环通过所有已注册的侦听器并在每个上面调用.event(event)。与Board相同,每次创建新片时都调用board.registerListener(piece),因为它决定事情正在发生,它可以告诉所有已注册的听众发生了什么。然后你可以告诉一块它不再由Board对象决定这一点。这是必须的维基百科entry

答案 2 :(得分:0)

我希望有一个代表每个形状的类(没有位置信息),一个包含形状,位置和方向的控制器,以及另一个代表当前生成的“着陆”形状网格的类。

可以使用落地网格
testLanded(shape, shapePosition, orientation)

在每次移动操作之前/之后调用的方法,用于确定形状是否要加入着陆网格,还是应该移动并保持为落下的部分。

我的想法是不向不应该拥有该数据的对象提供数据 - 但我从未实现过俄罗斯方块......

答案 3 :(得分:0)

您可能需要重新考虑您的设计。董事会真的需要跟踪掉落的部分还是应该属于BlockGrid?解决谁拥有什么行为。

保持您的Piece类的位置信息,并且可能让您的Piece类包含BlockGrid的实例。

然后你可以在你的Board类中尝试这样的事情......

public function moveFallingPiece(xDirection:int, yDirection:int):void
{
    blockGrid.moveFallingPiece(xDirection, yDirection);
}

然后在BlockGrid的moveFallingPiece方法......

public function moveFallingPiece(xDirection:int, yDirection:int):void
{
    fallingPiece.move(xDirection, yDirection);
}

在Piece的移动方法中,添加你的逻辑......

public function move(xDirection:int, yDirection:int):void
{
    setPosition(xDirection, yDirection);

    if (getPosition().y <= 0)
    {
        blockGrid.setFallingPiece(null); 
        // this can bubble up to Board if need be
    }
}

不确定AS3的所有功能,但在这里使用抽象是有意义的。 (即让你的Piece类依赖于ITrackFallingPieces而不是BlockGrid,并让BlockGrid实现ITrackFallingPieces)。

祝你好运!