Лучшее решение проблемы организации ООП - PullRequest
3 голосов
/ 22 декабря 2011

У меня быстрый вопрос об организации конкретной проблемы ООП.

Скажем, у меня есть класс Terrain, полный Tiles.Существует несколько производных класса Tile, а именно Door.Класс Door имеет метод open (), который открывает дверь, и close (), который закрывает дверь.Это имеет смысл, пока оба эти метода не проверят что-либо на пути перед открытием и / или закрытием.Как мне сделать проверку двери для объекта таким образом, чтобы он не знал о его родителе?

Простым решением было бы проверить что-то в пути перед вызовом open (), но если было другоедверь, которую нужно было проверить в другой форме, она создает беспорядок на более высоком уровне.

Кажется, что на это можно было бы дать простой ответ, но, похоже, я сталкиваюсь с этой проблемой чаще, чемнет.

1 Ответ

2 голосов
/ 22 декабря 2011

Один из ответов заключается в том, что двери должны знать, как открываться и закрываться, и знать, заблокированы ли они. Если Door - это класс, то и состояние ( is_open , is_blocked ) и поведение ( open_the_door , close_the_door ) должны находиться в Дверной класс. Инкапсуляция является фундаментальным принципом объектно-ориентированной парадигмы.

Но реальный ответ обычно более тонкий. Можете ли вы предоставить некоторые сведения о приложении и о том, что ему нужно для этого сделать? Есть чистые, простые решения, которые хорошо подойдут для игрушечных приложений, но более крупным приложениям потребуется нечто более сложное.

Как обращаться с дверью is_blocked представляет некоторые проблемы дизайна. Нет единого правильного дизайна, но есть хороший дизайн и плохой дизайн. Отделение хороших идей от плохих идей зависит не только от принципов проектирования - это зависит от контекста проблемы.

Если бы мне пришлось угадывать, я бы предположил, что ваше приложение - игра. Возможно, плитки представляют область игрового поля или карты. Вы определили, что многим различным объектам, возможно, придется взаимодействовать, и что будет беспорядок, если они все ссылаются друг на друга напрямую.

  • В играх часто есть главный объект, который называется «Игра», «Доска» или «Карта». Пусть главный объект содержит коллекцию вещей в иерархии плиток (плитки, двери и т. Д.).

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

  • Теперь создайте метод с именем update () в классе Tile, который принимает объект в качестве параметра.

  • И создайте логический атрибут для класса Door, который называется «заблокирован». Метод обновления для двери может сделать что-то вроде этого: <pre>Door::update(BlockingObject object) { if(object.location == this.location) blocked = true }

  • Метод надкласса двери может ничего не делать. Как это: <pre>Tile::update(BlockingObject obj) { //tiles cannot be blocked }

  • Теперь внутри игрового цикла включите шаг, в котором все двери установлены на blocked = false.

  • Циклы создания некоторых просят все плитки проверить, не заблокированы ли они. Это может выглядеть примерно так в псевдокоде: <pre>For each tile { For each blocking object { tile.update(object) } }

  • Это наивный, но прямой дизайн, который соответствует парадигме ОО.

  • Дизайн дает плиткам / дверям и объектам возможность взаимодействовать один раз за ход, не заставляя их хранить ссылки друг на друга.

  • Дизайн будет хорошо работать для нескольких сотен плиток и объектов, но он будет очень медленным для тысяч плиток.

Это хороший дизайн?

Ответ зависит от потребностей приложения.

...