Полиморфизм
Пока вы используете getType()
или что-то подобное, вы не используете полиморфизм.
Я понимаю, что тебе нужно знать, какой у тебя тип. Но любую работу, которую вы хотели бы выполнять, зная, что это действительно нужно отодвинуть в класс. Тогда просто скажи, когда это делать.
Процедурный кодекс получает информацию, затем принимает решения. Объектно-ориентированный код говорит объектам что-то делать.
- Алек Шарп
Этот принцип называется сказать, не спрашивайте . Следуя этому, вы не будете распространять детали типа текста и создавать логику, которая на них действует. Это превращает класс наизнанку. Лучше хранить это поведение внутри класса, чтобы оно могло меняться при изменении класса.
Инкапсуляция
Вы можете сказать мне, что никакие другие формы никогда не понадобятся, но я не верю вам и вам не следует.
Приятным эффектом последующей инкапсуляции является то, что легко добавлять новые типы, потому что их детали не распространяются на код, в котором они отображаются, if
и на switch
логику. Код для нового типа должен быть в одном месте.
Система обнаружения столкновений невежественного типа
Позвольте мне показать вам, как я спроектировал бы систему обнаружения столкновений, которая бы работала и работала с любой 2D-формой, не заботясь о типе.
Скажи, что ты должен был это нарисовать. Кажется простым Это все круги. Соблазнительно создать класс круга, который понимает столкновения. Проблема в том, что это заставляет нас задуматься, когда нам нужно 1000 кругов.
Мы не должны думать о кругах. Мы должны думать о пикселях.
Что если я скажу вам, что тот же код, который вы используете для рисования этих парней, - это то, что вы можете использовать, чтобы определить, когда они касаются или даже те, на которые нажимает пользователь.
Здесь я нарисовал каждый круг уникальным цветом (если ваши глаза достаточно хороши, чтобы увидеть черный контур, просто игнорируйте это). Это означает, что каждый пиксель в этом скрытом изображении соответствует тому, что нарисовало его. Хешмап позаботится об этом красиво. Вы действительно можете сделать полиморфизм таким образом.
Это изображение вам никогда не придется показывать пользователю. Вы создаете его с тем же кодом, который нарисовал первый. Просто с разными цветами.
Когда пользователь нажимает на круг, я точно знаю, какой круг, потому что этот цвет имеет только один круг.
Когда я рисую круг поверх другого, я могу быстро прочитать каждый пиксель, который я собираюсь перезаписать, поместив их в набор. Когда я закончил, установил точки для каждого круга, с которым он столкнулся, и теперь мне нужно всего лишь позвонить каждому из них, чтобы уведомить его о столкновении.
Новый тип: прямоугольники
Все это было сделано с кругами, но я спрашиваю вас: с прямоугольниками это будет работать иначе?
Никакие круговые знания не просочились в систему обнаружения. Его не волнует радиус, окружность или центральная точка. Это заботится о пикселях и цвете.
Единственная часть этой системы столкновений, которую необходимо придавить отдельным формам, - это уникальный цвет. Кроме этого формы могут просто думать о рисовании своих форм. Это то, что они хороши в любом случае.
Теперь, когда вы пишете логику столкновения, вам все равно, какой у вас подтип. Вы говорите ему, что он сталкивается, и он говорит вам, что он нашел под формой, которую притворяется рисовать. Не нужно знать тип. А это значит, что вы можете добавлять столько подтипов, сколько вам нужно, без необходимости обновлять код в других классах.
Варианты реализации
Действительно, это не обязательно должен быть уникальный цвет. Это могут быть реальные ссылки на объекты и сохранить уровень косвенности. Но те не выглядят так хорошо, когда нарисованы в этом ответе.
Это всего лишь один пример реализации. Там, безусловно, есть другие. Это должно было показать, что чем ближе вы позволяете этим подтипам формы придерживаться своей единственной ответственности, тем лучше работает вся система. Вероятно, существуют более быстрые и менее ресурсоемкие решения, но если они заставят меня распространять знания о подтипах вокруг, я бы не хотел использовать их даже при повышении производительности. Я бы не использовал их, если бы я явно не нуждался в них.
Двойная отправка
До сих пор я полностью игнорировал двойную отправку . Я сделал это, потому что мог. Пока логике столкновения не важно, какие два типа столкнулись, вам это не нужно. Если вам это не нужно, не используйте его. Если вы думаете, что вам это может понадобиться, отложите заниматься этим как можно дольше. Такое отношение называется ЯГНИ .
Если вы решили, что вам действительно нужны разные виды столкновений, спросите себя, действительно ли n подтипам формы нужно n 2 видов столкновений. До сих пор я работал очень усердно, чтобы упростить добавление другого подтипа формы. Я не хочу портить это реализацией двойной отправки, которая заставляет круги знать, что квадраты существуют.
Сколько видов столкновений существует? Немного спекулируя (опасная вещь) изобретает упругие столкновения (упругие), неупругие (липкие), энергичные (взрывные) и разрушительные (разрушительные). Их может быть больше, но если это меньше, чем n 2, давайте не будем чрезмерно проектировать наши столкновения.
Это означает, что когда моя торпеда поражает что-то, что получает урон, оно не должно ЗНАТЬ, что оно поражает космический корабль. Надо только сказать: «Ха-ха! Ты получил 5 единиц урона».
Вещи, которые наносят ущерб, отправляют сообщения об ущербе вещам, которые принимают сообщения о повреждении. Сделав это, вы можете добавлять новые фигуры, не рассказывая другим фигурам о новой фигуре. В итоге вы распространяетесь только вокруг новых типов столкновений.
Космический корабль может отправить обратно в оцепенение "Ха-ха! Вы получили 100 единиц урона". а также "Вы сейчас застряли в моем корпусе". И торп может отправить назад: «Ну, я готов, так что забудь обо мне».
Ни в коем случае не знает точно, что каждый из них. Они просто знают, как разговаривать друг с другом через интерфейс столкновения.
Конечно, двойная диспетчеризация позволяет вам контролировать вещи более тщательно, чем это, но вы действительно этого хотите ?
Если вы, пожалуйста, хотя бы подумайте о том, чтобы выполнить двойную диспетчеризацию через абстракции того, какие виды столкновений принимает фигура, а не о фактической реализации фигуры. Кроме того, поведение при столкновении - это то, что вы можете внедрить в качестве зависимости и делегировать этой зависимости.
Производительность
Производительность всегда важна. Но это не значит, что это всегда проблема. Тест производительности. Не просто спекулировать. Пожертвование всем остальным во имя исполнения обычно не приводит к коду исполнения.