Как думать "Скажи, не спрашивай" в этом простом примере?
Как бы вы придерживались принципа "говори, не спрашивай" (далее "принцип") в следующем простом сценарии? В игре 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);
}
}
После того, как fallPiece помещен в нижний ряд 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 ответа
Я думаю, чтобы лучше следовать принципу "Говори, а не спрашивай", вы должны иметь blockGrid, уведомляющее ваш класс Board, когда fallPiece достигает своей точки покоя. В обоих вышеописанных сценариях вы спрашиваете blockGrid, является ли элемент position.y == 0, чтобы определить, должен ли нуль-фрагмент не иметь значения. Вместо этого вы хотите, чтобы blockGrid сообщал классу Board о том, что fallPiece.y достиг 0.
То, что вы ищете, это программирование на основе событий. Вам нужен интерфейс Listener с методом.event() и интерфейсом Event для представления событий. Объекты будут регистрироваться с другими объектами (обратными вызовами) для интерфейса слушателя.
когда вы создаете Piece и Board, они должны реализовывать интерфейс Listener. Затем вы можете установить плату с помощью registerListener(доска); Затем, когда что-то происходит внутри Piece, он будет проходить через всех зарегистрированных слушателей и вызывать.event (событие) для каждого. Как и в случае с Board, вызывайте board.registerListener(piece) каждый раз, когда вы создаете новый фрагмент, так как он решает, что что-то происходит, и может сообщить всем зарегистрированным слушателям, что произошло. Затем вы можете сказать фигуре, что она больше не падает объектом Board, решая это. Вот обязательная запись в Википедии.
Я ожидаю, что класс, представляющий каждую фигуру (без информации о положении), контроллер, содержащий форму, положение и ориентацию, и другой класс, представляющий текущую результирующую сетку "приземленных" фигур. Приземленная сетка будет иметь
testLanded(shape, shapePosition, orientation)
метод, который будет вызываться до / после каждой операции перемещения, чтобы решить, должна ли фигура присоединиться к приземленной сетке или должна двигаться и оставаться как падающая фигура.
Я собираюсь не давать данные объектам, которые не должны действительно владеть этими данными - но я никогда не использовал Tetris...
Возможно, вам придется пересмотреть свой дизайн. Действительно ли 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).
Удачи!