4

在以下简单场景中,您将如何坚持“告诉,不问”原则(以下简称“原则”)?在俄罗斯方块游戏中,我有与以下示例相关的 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);
    }
} 

一旦fallingPiece 放置在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

4 回答 4

1

我认为,为了更好地遵循告诉,不问的原则,你应该让 blockGrid 在fallingPiece 达到它的静止点时通知你的 Board 类。在上述两种情况下,您都在询问 blockGrid 片段的 position.y == 0 以确定fallPiece 是否应该为空。相反,您希望 blockGrid 告诉 Board 类fallingPiece.y 已达到 0。

于 2010-02-07T01:27:46.710 回答
1

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

当您创建 Piece 和 Board 时,它们应该实现 Listener 接口。然后你可以用 registerListener(board); 设置 Board;然后,当 Piece 内部发生事情时,它将遍历所有已注册的侦听器并在每个侦听器上调用 .event(event)。与 Board 相同,每次创建新片段时都调用 board.registerListener(piece),因为它决定事情正在发生,它可以告诉所有注册的听众发生了什么。然后,您可以通过决定这一点的 Board 对象来判断一块它不再掉落。这是强制性的维基百科条目

于 2010-02-07T02:17:08.887 回答
0

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

testLanded(shape, shapePosition, orientation)

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

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

于 2010-02-07T01:59:25.840 回答
0

您可能需要重新考虑您的设计。Board 真的需要跟踪下落的部分还是应该属于 BlockGrid?找出谁拥有什么行为。

在您的 Piece 类上保留位置信息,并可能让您的 Piece 类持有 BlockGrid 的实例。

然后你可以在你的董事会课上尝试这样的事情......

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 的 move 方法中,添加您的逻辑...

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)。

祝你好运!

于 2010-02-07T04:13:14.230 回答