Я изучаю развитие, основанное на тестах, и я заметил, что он заставляет свободно связанные объекты, что в принципе хорошо. Однако это также иногда заставляет меня предоставлять аксессуры для свойств, которые мне не нужны в обычном режиме, и я думаю, что большинство людей на SO согласны с тем, что аксессоры обычно являются признаком плохого дизайна. Это неизбежно при выполнении TDD?
Вот пример упрощенного кода чертежа объекта без TDD:
class Entity {
private int x;
private int y;
private int width;
private int height;
void draw(Graphics g) {
g.drawRect(x, y, width, height);
}
}
Сущность знает, как рисовать себя, что хорошо. Все в одном месте. Тем не менее, я делаю TDD, поэтому я хочу проверить, правильно ли перемещен мой объект методом fall(), который я собираюсь реализовать. Вот как выглядит тестовый пример:
@Test
public void entityFalls() {
Entity e = new Entity();
int previousY = e.getY();
e.fall();
assertTrue(previousY < e.getY());
}
Мне нужно посмотреть на внутреннее (ну, по крайней мере, логически) состояние объекта и посмотреть, правильно ли была обновлена позиция. Так как это на самом деле (я не хочу, чтобы мои тестовые примеры зависели от моей графической библиотеки), я переместил код чертежа в класс "Renderer":
class Renderer {
void drawEntity(Graphics g, Entity e) {
g.drawRect(e.getX(), e.getY(), e.getWidth(), e.getHeight());
}
}
Плохо связанный, хороший. Я даже могу заменить средство визуализации тем, что отображает объект совершенно по-другому. Однако мне пришлось разоблачить внутреннее состояние объекта, а именно аксессоров для всех его свойств, чтобы визуализатор мог его прочитать.
Я чувствую, что это было специально вызвано TDD. Что я могу сделать по этому поводу? Является ли мой дизайн приемлемым? Требует ли Java ключевое слово "friend" из С++?
Update:
Спасибо за ваши ценные данные! Однако, боюсь, я выбрал плохой пример для иллюстрации моей проблемы. Это было полностью выполнено, теперь я продемонстрирую тот, который ближе к моему фактическому коду:
@Test
public void entityFalls() {
game.tick();
Entity initialEntity = mockRenderer.currentEntity;
int numTicks = mockRenderer.gameArea.height
- mockRenderer.currentEntity.getHeight();
for (int i = 0; i < numTicks; i++)
game.tick();
assertSame(initialEntity, mockRenderer.currentEntity);
game.tick();
assertNotSame(initialEntity, mockRenderer.currentEntity);
assertEquals(initialEntity.getY() + initialEntity.getHeight(),
mockRenderer.gameArea.height);
}
Это игра на основе игры, основанная на игре, где сущность может упасть, между прочим. Если он попадает на землю, создается новый объект.
"mockRenderer" - это макетная реализация интерфейса "Renderer". Этот дизайн был частично вынужден TDD, но также из-за того, что я собираюсь написать пользовательский интерфейс в GWT, и в браузере пока нет явного чертежа, поэтому я не думаю, что это возможно для класс Entity, чтобы взять на себя эту ответственность. Кроме того, я хотел бы сохранить возможность переноса игры на родную Java/Swing в будущем.
Обновление 2:
Размышляя об этом, возможно, все в порядке, как это. Возможно, хорошо, что объект и чертеж отделены друг от друга и что объект сообщает другим объектам достаточно о себе для рисования. Я имею в виду, как еще я мог бы достичь этого разделения? И я не вижу, как жить без него. Даже великие объектно-ориентированные программисты иногда используют объекты с геттерами/сеттерами, особенно для чего-то вроде объекта сущности. Может быть, геттер/сеттер не все злы. Как вы думаете?