Поліморфізм
Поки ви використовуєте getType()
чи щось подібне, ви не використовуєте поліморфізм.
Я розумію, відчуваю, що вам потрібно знати, який у вас тип. Але будь-яку роботу, яку ви хотіли б зробити, знаючи, що її справді слід відсунути в клас. Тоді ви просто скажете, коли це зробити.
Процедурний код отримує інформацію, після чого приймає рішення. Об'єктно-орієнтований код повідомляє об'єктам робити речі.
- Алек Шарп
Цей принцип називається скажи, не питай . Дотримуючись це, ви допомагаєте не поширювати деталі на зразок типу навколо та створювати логіку, яка діє на них. Це перетворює клас назовні. Краще зберігати таку поведінку всередині класу, щоб вона могла змінюватися, коли клас змінювався.
Інкапсуляція
Ви можете сказати мені, що інші форми ніколи не знадобляться, але я не вірю вам, а також вам.
Приємним ефектом після інкапсуляції є те, що легко додавати нові типи, оскільки їх деталі не поширюються в код, де вони відображаються, if
і switch
логіка. Код нового типу повинен бути в одному місці.
Невідома система виявлення зіткнень
Дозвольте мені показати вам, як я б спроектував систему виявлення зіткнень, яка працює та працює з будь-якою двовимірною формою, не піклуючись про тип.
Скажіть, ви повинні це намалювати. Здається, просто. Це всі кола. Заманливо створити клас гуртка, який розуміє зіткнення. Проблема полягає в тому, що це направляє нас вниз по лінії мислення, яка розпадається, коли нам потрібно 1000 кіл.
Ми не повинні думати про кола. Ми повинні думати про пікселі.
Що робити, якщо я сказав вам, що той самий код, який ви використовуєте для малювання цих хлопців, - це те, що ви можете використовувати для виявлення, коли вони торкаються або навіть того, на який користувач натискає.
Тут я намалював кожне коло унікальним кольором (якщо ваші очі досить гарні, щоб побачити чорний контур, просто проігноруйте це). Це означає, що кожен піксель у цьому прихованому зображенні відображається до того, що його намалювало. Хешмап добре піклується про це. Насправді можна зробити поліморфізм таким чином.
Це зображення ви ніколи не повинні показувати користувачеві. Ви створюєте його з тим самим кодом, який намалював перший. Просто з різними кольорами.
Коли користувач натискає коло, я точно знаю, яке коло, тому що лише одне коло - це колір.
Коли я намалюю коло поверх іншого, я можу швидко прочитати кожен піксель, який я збираюся перезаписати, скинувши їх у набір. Коли я закінчив встановити крапки для кожного кола, в яке він зіткнувся, і мені залишається лише один раз зателефонувати кожному, щоб повідомити про зіткнення.
Новий тип: Прямокутники
Це все робилося за допомогою кіл, але я запитаю вас: чи не працювало б воно з прямокутниками?
Жодна інформація про коло не просочилася в систему виявлення. Це не хвилює радіус, окружність або центральну точку. Це піклується про пікселі та кольорі.
Єдина частина цієї системи зіткнень, яку потрібно відсунути в окремі форми, - це унікальний колір. Крім того, фігури можуть просто думати про малювання своїх фігур. Це все, що їм добре.
Тепер, коли ви пишете логіку зіткнення, вам не байдуже, який у вас підтип. Ви кажете йому зіткнутися, і він розповість вам, що він знайшов під формою, яку прикидається малювати. Не потрібно знати тип. А це означає, що ви можете додати скільки завгодно підтипів, не потребуючи оновлення коду в інших класах.
Реалізація варіантів
Дійсно, це не потрібно, щоб це був унікальний колір. Це можуть бути фактичні посилання на об'єкт і зберегти рівень непрямості. Але це не виглядало б так приємно, коли звертається у цій відповіді.
Це лише один приклад реалізації. Звичайно, є й інші. Що це означало показати, що чим ближче ви дозволяєте цим підтипам форми дотримуватися своєї єдиної відповідальності, тим краще працює вся система. Ймовірно, є швидші та менш об'ємні оперативні пам’яті, але якщо вони змусять мене поширювати знання про підтипи навколо, я б ненавиджу використовувати їх навіть із збільшенням продуктивності. Я б не користувався ними, якщо я їх явно не потребував.
Подвійна відправка
До цих пір я повністю ігнорував подвійну розсилку . Я це зробив, бо міг. До тих пір, поки логіку зіткнення не хвилює, які два типи зіткнулися, вам це не потрібно. Якщо він вам не потрібен, не використовуйте його. Якщо ви думаєте, що вам це може знадобитися, відкладіть справу, поки зможете. Таке ставлення називається ЯГНІ .
Якщо ви вирішили, що вам справді потрібні різні види зіткнень, то запитайте себе, чи потрібні підтипи n форми справді n 2 видів зіткнень. Поки я дуже наполегливо працював, щоб легко додати ще один підтип форми. Я не хочу зіпсувати це подвійною диспетчерською реалізацією, яка змушує кола знати, що квадрати існують.
Скільки видів зіткнень все-таки є? Трохи міркуючи (небезпечна річ) вигадує пружні зіткнення (підстрибування), нееластичні (липкі), енергійні (вибухові) та руйнівні (пошкодження). Може бути і більше, але якщо це менше n 2, то не можемо сконструювати наші зіткнення.
Це означає, що коли моя торпеда потрапляє на щось, що сприймає шкоду, не потрібно її знати, коли вона потрапила в космічний корабель. Треба лише сказати: "Ха-ха! Ти забрав 5 балів шкоди".
Речі, які завдають шкоди, надсилають повідомлення про пошкодження речам, які приймають повідомлення про пошкодження. Зроблено таким чином, ви можете додавати нові форми, не повідомляючи іншим про нову форму. Ви лише поширюєтесь навколо нових типів зіткнень.
Космічний корабель може відправити назад на торп "Ха-ха! Ти забрав 100 очок шкоди". а також "Ти зараз причепився до мого корпусу". І торп може відправити назад "Ну, я готовий, щоб забути про мене".
Жоден момент не знає, що саме таке кожен. Вони просто знають, як спілкуватися один з одним через інтерфейс зіткнення.
Тепер впевнене, що подвійна відправка дозволяє контролювати речі більш інтимно, ніж це, але чи справді ви цього хочете ?
Якщо ви хочете, подумайте, принаймні, подумайте про подвійну диспетчеризацію абстракцій про те, які види зіткнень приймає форма, а не над реальною реалізацією форми. Також поведінка зіткнення - це те, що можна ввести як залежність і делегувати цю залежність.
Продуктивність
Продуктивність завжди критична. Але це не означає, що це завжди проблема. Виконання тесту. Не просто спекулюйте. Жертвоприношення всього іншого в ім'я продуктивності зазвичай не призводить до коду виконання.