Я изучаю разработку, основанную на тестах, и заметил, что она вызывает слабосвязанные объекты, что в принципе хорошо.Однако это также иногда вынуждает меня предоставлять средства доступа для свойств, которые мне обычно не нужны, и я думаю, что большинство людей в 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" из C ++?
Обновление:
Спасибо за ваш ценный вклад!Однако я боюсь, что выбрал плохой пример для иллюстрации своей проблемы.Это было полностью сделано, сейчас я продемонстрирую тот, который ближе к моему фактическому коду:
@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, и нет явного рисования в браузере (пока), поэтому я не думаю, что это возможно дляСущность класса, чтобы взять на себя эту ответственность.Кроме того, я хотел бы сохранить возможность портирования игры на нативный Java / Swing в будущем.
Обновление 2:
Думая об этом еще немного, возможноэто нормально, как это.Может быть, это нормально, что сущность и рисунок разделены и что сущность достаточно рассказывает другим объектам о себе, чтобы нарисовать.Я имею в виду, как еще я мог достичь этого разделения?И я не вижу, как жить без этого.Даже великие объектно-ориентированные программисты иногда используют объекты с геттерами / сеттерами, особенно для чего-то вроде объекта сущности.Может быть, геттер / сеттер не все злые.Что ты думаешь?