Как думать «Скажи, не спрашивай» в этом простом примере? - PullRequest
4 голосов
/ 07 февраля 2010

Как бы вы придерживались принципа «говори, не спрашивай» (далее «принцип») в следующем простом сценарии? В игре Tetris у меня есть классы 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);
    }
} 

Как только падающий элемент помещен в нижний ряд BlockGrid, он больше не должен быть «падающим элементом». Прав ли я в том, что я не нарушаю принцип со следующим?

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

Я не предполагаю, что я спроектировал эти классовые отношения надлежащим образом для работы с принципом. Пожалуйста, совет по альтернативному дизайну, если это то, что мне не хватает.


РЕДАКТИРОВАТЬ, Предлагаемое решение:

Я пошел с ответами, предлагающими «командную обратную связь» через события. Доска говорит BlockGrid о перемещении фигуры. Метод movePiece от BlockGrid отправляет события 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 ]

1 голос
/ 07 февраля 2010

То, что вы ищете, это программирование на основе событий. Вам нужен интерфейс Listener с методом .event () и интерфейсом Event для представления событий. Объекты будут регистрироваться с другими объектами (обратными вызовами) к интерфейсу слушателя.

когда вы создаете Piece и Board, они должны реализовывать интерфейс Listener. Затем вы можете установить плату с помощью registerListener (доска); Затем, когда что-то происходит внутри Piece, он будет проходить через всех зарегистрированных слушателей и вызывать .event (событие) для каждого. Как и в случае с Board, вызывайте board.registerListener (piece) каждый раз, когда вы создаете новый фрагмент, так как он решает, что что-то происходит, и может сообщить всем зарегистрированным слушателям, что произошло. Затем вы можете сказать фигуре, что она больше не падает объектом Board, решая это. Вот обязательная Википедия запись .

1 голос
/ 07 февраля 2010

Я думаю, чтобы лучше следовать принципу "Говори, а не спрашивай", у тебя должна быть blockGrid, уведомляющая класс твоей доски о том, что fallPiece достигает своей точки покоя. В обоих вышеописанных сценариях вы спрашиваете blockGrid, является ли элемент position.y == 0, чтобы определить, должен ли нуль-фрагмент не иметь значения. Вместо этого вы хотите, чтобы blockGrid сообщал классу Board, что fallPiece.y достиг 0.

0 голосов
/ 07 февраля 2010

Возможно, вам придется пересмотреть свой дизайн. Действительно ли Board необходимо отслеживать падающий предмет или он должен принадлежать BlockGrid? Сгладьте, кто каким поведением владеет.

Сохраните информацию о позиции в вашем классе Piece и, возможно, ваш класс Piece будет содержать экземпляр BlockGrid.

Затем вы можете попробовать что-то подобное в своем классе доски ...

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

Затем в методе MoveFallingPiece блока BlockGrid ...

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

Удачи!

0 голосов
/ 07 февраля 2010

Я ожидаю, что класс, представляющий каждую фигуру (без информации о положении), контроллер, содержащий форму, положение и ориентацию, и другой класс, представляющий текущую результирующую сетку «приземленных» фигур. Приземленная сетка будет иметь

testLanded(shape, shapePosition, orientation)

метод, который вызывается до / после каждой операции перемещения, чтобы определить, должна ли фигура присоединиться к приземленной решетке или она должна двигаться и оставаться в качестве падающей фигуры.

Я собираюсь не отдавать данные объектам, которым эти данные не принадлежат, но я никогда не использовал Tetris ...

...