Яка закономірність це, і чи потрібно це робити?


9

Я роблю гру в as3, використовуючи flash development та flash cs5. Все об’єктно орієнтоване. Мені було цікаво, чи повинен я мати один "шлюзний" клас, який має властивість-посилання на всі інстанції інших класів, і я просто передаю цей клас шлюзу новим об'єктам, щоб вони мали доступ до кожного класу. Так:

 var block:Block = new Block(gateway);

 //In the block class:
 this.gateway.player.setHealth(100);
 //Or:
 this.gateway.input.lock();

Це схоже на однотонний візерунок чи щось таке? Чи варто це робити?

Відповіді:


13

Це називається шаблоном дизайну контекстного об'єкта , і він краще, ніж однотонний.

  • Об'єкти контексту допомагають тестувати, оскільки ви можете передавати макетні контексти функціям, які ви хочете перевірити. Однотонні перешкоджають цьому, тому що для знущання з одинаків вам потрібно зробити їх не сингтонами.
  • Об'єкти контексту роблять ваше "глобальне стан" явним, а тому простіше міркувати. Якщо функція не приймає контекстний об'єкт, ви знаєте, що він не використовує жодного глобального стану контексту. У вас немає жодної гарантії з одиночними кнопками або глобальними змінними.
  • Об'єкти контексту дуже повільно, якщо ви не використовуєте їх, оскільки ви додаєте інший параметр до всіх функцій викликів. Якщо ви користуєтесь ними, вони можуть бути швидшими, ніж глобальні, і майже завжди швидші, ніж одинаки.
  • Об'єкти контексту легше реалізувати; зазвичай вони живуть на купі або штабелі нормальним чином. У одиночних є складні проблеми, пов’язані з нанизуванням на багатьох мовах.

Так що ні, це не синглтон, це краще, ніж синглтон.

Однак ви все ще обходите згубний стан - той факт, що ви зберігаєте все це в одній локальній змінній, робить це більш явним, але все ще створює великі проблеми . Майте на увазі одне правило відповідальності . Має сенс існувати контекст, який належить плеєру та поточний рівень - вони пов'язані - але чому той самий контекст володіє вашим вкладом на клавіатурі?

Розглянемо різні рівні контекстів, наприклад:

  • GameplayContext - володіє гравцем, ворогами, геометрією рівня тощо.
  • InputContext - володіє ручками клавіатури та миші, подіями введення тощо.
  • GraphicsContext - володіє текстурами, ручкою вікна тощо.
  • GlobalContext - володіє GameplayContext, GraphicsContext та InputContext. Тут ви хочете застосувати шаблон локатора служб , щоб мати можливість замінювати деякі контексти на інші за потребою. І, можливо, для швидкої ітерації та тестування це повинно бути реальною глобальною змінною - просто розумійте, що кожного разу, коли ви користуєтесь нею, ви нарощуєте технічну заборгованість .

Цей контекст все ще викликає занепокоєння - можливо, якийсь обробник подій приймає GameplayContext і справді потрібен лише гравцеві - але обов'язки чітко викладені. Ви знаєте, що те, що займає GameplayContext, не завантажує текстуру; щось, що бере InputContext, не може вбити гравця.


+1 Хороша відповідь. Деякі проблеми, пов'язані зі швидкістю чи нанизуванням, насправді не застосовуються в цьому контексті (ActionScript3 не підтримує різьблення, і багато механізмів підвищення швидкості, які працюють у C ++, не застосовуються під час використання AS3).
bummzack

Я не знаю багато про AS3VM, але в більшості динамічних мов вартість передачі / прийому / використання локального все ще швидша (пошук масиву), ніж вартість пошуку глобального (хеш-пошуку), і набагато швидше, ніж виклик функції (craploads речі), щоб отримати її. Тому я думаю, що порада все-таки діє.

0

Це не схоже на шаблон Singleton. Як я це розумію, ви передаєте об'єкт із посиланнями на важливі ігрові об’єкти у всі ваші екземпляри.

Якщо це буде візерунок Сінглтона, у вас буде:

AudioManager.getInstance().playSound(XY);

Тоді як у вашому випадку у вас можуть бути:

this.gateway.getAudioManager().playSound(XY);

Це виглядає в основному так само, але насправді це не так. Якщо ви хочете замінити AudioManagerна новий (розширений клас) на зразок ExtendedAudioManager, ви б'єте по стіні за допомогою шаблону Singleton. Ваш підхід до шлюзу впорається з цим просто добре.

Недолік вашого підходу полягає в тому, що вам доведеться обходити gatewayвсюди всюди. Шаблон локатора служби (запропонований Джо Wreschnig в цій темі), виглядає як заміна хорошою для вашого «шаблону шлюзу».

Іноді краще просто запустити простий і простий метод, а не надмірно розробляти речі. Особливо, коли це невеликий проект чи прототип. Можливо, ви могли б зробити gatewayякусь глобальну змінну .. наприклад. Game.gatewayі біжи з ним.


-2

Більшість рішень цієї проблеми, включаючи схему Сінглтона, передбачають використання статичних змінних. Якщо у вас буде тільки один гравець, ви можете просто мати Player для однотонного класу, а це означає, що ви могли отримати доступ до екземпляра Player через щось на зразок Player.currentPlayer. Однак багато людей лютують проти Сінглтона. Ви також можете мати ResourceManager або подібний клас, який містить статичні посилання на різні корисні глобальні або досить-чортово-глобальні змінні. У своєму коді ви також можете зробити змінні "Шлюз" статично доступними, а не надувати код, передаючи його скрізь.


Питання суттєво змінилося з моменту того, як я дав цю відповідь, досить, що редагувати її, здається, не варто.
Григорій Евері-Вейр

2
Крім назви, у питанні нічого не змінилося.
bummzack

1
Що? Ніщо не змінилося, крім назви. -1
AttackingHobo

Думаю, я тут думав над заголовком; Я пам'ятаю, що оригінальна назва була чимось на кшталт "Як мені це зробити?" Цілком можливо, що я неправильно прочитав початкову назву / питання, коли зробив відповідь.
Григорій Ейвері-Вейр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.