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

发布于 2024-08-20 04:10:43 字数 1712 浏览 3 评论 0原文

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

How would you adhere to the "Tell, don't ask" principle (henceforth "the principle") in the following simple scenario? In a Tetris game, I have Board, BlockGrid and Piece classes relevant to the following example:

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

Once fallingPiece is placed in the bottom row of BlockGrid, it should no longer be the "fallingPiece". Am I right in that I'm not violating the principle with the following?

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

But is that really different from this, which I think clearly violates the principle?

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

I'm not assuming that I've designed these class relationships in the proper way to work with the principle. Please advice on an alternate design if that's what I'm missing.


EDIT, Proposed solution:

I went with the answers proposing "command feedback" via events. Board tells BlockGrid to move a piece. BlockGrid's movePiece method dispatches MOVED_TO or MOVE_FAILED events depending on the result, which Board can listen to and use to determine whether a piece has stopped falling. Please don't hesitate to provide feedback on this solution.

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;
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寒尘 2024-08-27 04:10:43

我认为,为了更好地遵循“告诉,不要问”原则,当落下的棋子到达其静止点时,您应该让 blockGrid 通知您的 Board 类。在上面的两种情况下,您都询问 blockGrid 棋子的position.y == 0 以确定fallingPiece 是否应该为null。相反,您希望 blockGrid 告诉 Board 类fallingPiece.y 已达到 0。

I think, to better follow the Tell, Don't Ask principle, you should have blockGrid notifying your Board class when fallingPiece has reaches it's resting point. In both scenarios above, you are asking blockGrid if the piece's position.y == 0 in order to determine whether or not fallingPiece should be null. Instead, you want blockGrid to tell the Board class that fallingPiece.y has hit 0.

时光与爱终年不遇 2024-08-27 04:10:43

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

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

What you are looking for is Event driven programming. You need a Listener interface with a method called .event() and an Event interface to represent the events. Objects will register with other objects ( callbacks ) to the Listener interface.

when you create a Piece and Board they should implement the Listener interface. Then you can set the Board with registerListener(board); Then when things happen inside Piece it will loop thru all the registered listeners and call .event(event) on each. Same with the Board, call board.registerListener(piece) each time you create a new piece, as it decides things are happening it can tell all the registered listeners what has happened. Then you can tell a piece it is no longer falling by the Board object deciding this. Here is the obligitory Wikipedia entry.

鯉魚旗 2024-08-27 04:10:43

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

testLanded(shape, shapePosition, orientation)

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

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

I would expect a class representing each shape (without position information), a controller containing a shape, position and orientation, and another class representing the current resulting grid of "landed" shapes. The landed-grid would have a

testLanded(shape, shapePosition, orientation)

method which would be called before/after each move operation to decide if the shape is to join the landed grid or should move and stay as the falling piece.

I'm going on the idea of not giving data to objects that shouldn't really own that data - but I've never implemented Tetris...

南笙 2024-08-27 04:10:43

您可能需要重新考虑您的设计。 Board 是否真的需要跟踪下落的棋子,还是应该属于 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 的 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)。

祝你好运!

You may need to rethink your design. Does Board really need to track the falling piece or should that belong to BlockGrid? Iron out who owns what behavior.

Keep position information on your Piece class and possibly have your Piece class hold an instance of the BlockGrid.

You can then try something like this in your Board class...

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

Then in BlockGrid's moveFallingPiece method...

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

In Piece's move method, add your logic...

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
    }
}

Not sure of all the power of AS3, but it would make sense to use abstractions here. (i.e., have your Piece class depend on ITrackFallingPieces instead of BlockGrid and have BlockGrid implement ITrackFallingPieces).

Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文