Game Programming Patterns / Паттерны программирования в играх: 1.3. Observer
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
Будь это реальным кодом, я бы сделал так. kamillxiii 03.05.14 в 14:29 В реальном коде я бы сделал так. IngaJolly 31.08.14 в 19:16 |
|
|
Всё, что осталось, это отправить оповещение. kamillxiii 03.05.14 в 14:29 Осталось только отправить уведомление. IngaJolly 31.08.14 в 19:16 |
||
|
Это не сложнее, чем простой обход списка. kamillxiii 03.05.14 в 14:30 Это так же просто, как обход списка: IngaJolly 31.08.14 в 19:16 |
||
|
void Subject::notify(const Entity& entity, Event event) kamillxiii 03.05.14 в 14:30 |
||
|
{ kamillxiii 03.05.14 в 14:30 |
||
|
Observer* observer = head_; kamillxiii 03.05.14 в 14:30 |
||
|
while (observer != NULL) kamillxiii 03.05.14 в 14:30 |
||
|
{ kamillxiii 03.05.14 в 14:30 |
||
|
observer->onNotify(entity, event) kamillxiii 03.05.14 в 14:30 |
||
|
; kamillxiii 03.05.14 в 14:30 |
||
|
observer = observer->next_; kamillxiii 03.05.14 в 14:30 |
||
|
} kamillxiii 03.05.14 в 14:30 |
||
|
} kamillxiii 03.05.14 в 14:30 |
||
|
Тут мы обходи весь список и оповещаем каждого наблюдателя. kamillxiii 05.05.14 в 11:06 Обходим весь список и уведомляем каждого наблюдателя из него. IngaJolly 31.08.14 в 19:17 |
||
|
Благодаря этому, наблюдатели имеют равный приоритет, а также независимость друг от друга. kSky7000 06.05.14 в 05:14 Теперь все наблюдатели имеют одинаковый приоритет и независимы друг от друга. IngaJolly 31.08.14 в 19:18 |
||
|
Можно немного модифицировать этот код. Например при получении наблюдателем оповещения, он возвратит флаг, показывающий, нужно ли продолжать движение по списку или остановиться. kSky7000 06.05.14 в 10:24 Можно настроить так, чтобы при уведомлении наблюдателя возвращался флаг, нужно ли субъекту продолжить обход списка. IngaJolly 31.08.14 в 19:19 |
||
|
Если сделаете это, считайте что вплотную приблизились к паттерну Chain of Responsibility. kSky7000 06.05.14 в 10:33 Сделав это, максимально приблизимся к паттерну "Цепочка обязанностей" (Chain of Responsibility). IngaJolly 31.08.14 в 19:21 |
||
|
Неплохо, не так ли? kSky7000 06.05.14 в 10:34 Неплохо, правда? IngaJolly 31.08.14 в 19:21 |
||
|
Субъект может иметь столько наблюдателей, сколько захочет, без единого намека на динамическое выделение памяти. kSky7000 06.05.14 в 10:37 Субъект может иметь неограниченное количество наблюдателей без намека на динамическую память. IngaJolly 31.08.14 в 19:22 |
||
|
И теперь это работает также быстро, как это было с простым массивом. kSky7000 06.05.14 в 10:47 А изменение списка производится так же быстро, как и у обычного массива. kamillxiii 06.05.14 в 13:57 Регистрация и прекращение регистрации происходят так же быстро, как и в случае с простым массивом. IngaJolly 31.08.14 в 19:24 |
||
|
Однако, ради этого мы пожертвовали небольшой особенностью. kSky7000 06.05.14 в 10:50 Хотя мы пожертвовали небольшой возможностью. IngaJolly 31.08.14 в 19:25 |
||
|
При использовании объекта наблюдателя как узла в списке, необходимо учитывать одно ограничение: наблюдатель может быть частью только одного списка. kSky7000 06.05.14 в 11:09 Объект наблюдателя в качестве узла списка может находиться только в одном списке субъекта. IngaJolly 31.08.14 в 19:27 |
||
|
Другими словами, наблюдатель может следить только за одним субъектом. kSky7000 06.05.14 в 11:12 Другими словами, наблюдатель может следить только за одним субъектом в данный промежуток времени. IngaJolly 31.08.14 в 19:28 |
||
|
В более традиционной реализации, где каждый субъект имеет свой независимый список, наблюдатель может находиться в нескольких списках одновременно. kSky7000 06.05.14 в 11:18 |
||
|
Вас вполне могут не волновать подобные ограничения. kSky7000 06.05.14 в 11:21 Можно жить и с этим ограничением. IngaJolly 01.09.14 в 16:24 |
||
|
Я думаю, чаще всего субъект имеет нескольких наблюдателей, чем наоборот. kSky7000 06.05.14 в 11:31 Естественнее для субъекта иметь нескольких наблюдателей, чем наоборот. IngaJolly 01.09.14 в 16:25 |
||
|
Но если вас это интересует, есть одно более комплексное решение, все еще не требующее динамической работы с памятью. kSky7000 06.05.14 в 11:32 Но если это является проблемой, есть другое, более сложное решение, также не требующее динамического выделения. IngaJolly 01.09.14 в 16:25 |
||
|
Не думаю что смогу уместить его в эту главу, но я сделаю набросок и думаю вы все поймете. kSky7000 06.05.14 в 11:36 Он не вместится в главу целиком, но я приведу отрывок, позволив самостоятельно заполнить пробелы. IngaJolly 01.09.14 в 16:27 |
||
|
Пул узлов списка. kSky7000 06.05.14 в 11:36 Пул узлов списка IngaJolly 01.09.14 в 16:27 |
||
|
Как и раньше, каждый субъект имеет связный список наблюдателей. kSky7000 06.05.14 в 11:37 Как прежде, каждый субъект имеет связанный список наблюдателей. IngaJolly 01.09.14 в 16:27 |
||
|
Тем не менее, эти узлы списка не будут объектами наблюдателя сами. kSky7000 06.05.14 в 11:45 Однако узлы этого списка не являются объектами наблюдателя. IngaJolly 01.09.14 в 16:28 |
||
|
Вместо этого, объект узла списка будет содержать указатель на наблюдателя, и указатель на следующий узел в списке. kSky7000 06.05.14 в 11:51 Вместо этого, они представляют собой отдельные малые объекты "узла списка", содержащие указатель на наблюдателя и указатель на следующий узел в списке. IngaJolly 01.09.14 в 16:30 |
||
|
Потому как на одного наблюдателя может указывать множество узлов, этот наблюдатель может следить более чем за одним субъектом. kamillxiii 06.05.14 в 14:00 Из того, что несколько узлов могут указывать на одного наблюдателя, следует, что наблюдатель может находиться в нескольких списках субъекта в одно и то же время. IngaJolly 01.09.14 в 16:31 |
||
|
Мы вернули возможность наблюдать несколькими субъектами за раз. kamillxiii 06.05.14 в 14:01 Теперь можно снова наблюдать за несколькими субъектами одновременно. IngaJolly 01.09.14 в 16:59 |
||
|
Связанные списки бывают двух видов. kamillxiii 06.05.14 в 14:02 |
||
|
В первом, который вам известен со школы, есть узел, в котором хранятся данные. kamillxiii 06.05.14 в 14:03 В первом, который проходят в школе, есть узловой объект, содержащий данные. IngaJolly 01.09.14 в 17:20 |
||
|
В предыдущем примере с наблюдателем все было наоборот: данные (в данном случае, сам наблюдатель) содержат ссылку на узел (например, next_pointer). kamillxiii 06.05.14 в 14:07 В предыдущем примере со связанным наблюдателем было наоборот: данные (в данном случае, наблюдатель) IngaJolly 01.09.14 в 17:22 |
||
|
- kamillxiii 06.05.14 в 14:08 содержали узел (то IngaJolly 01.09.14 в 17:22 |
||
|
- kamillxiii 06.05.14 в 14:08 есть, IngaJolly 01.09.14 в 17:22 |
||
|
- kamillxiii 06.05.14 в 14:08 указатель next_). IngaJolly 01.09.14 в 17:22 |
||
|
Последний вариант называется "навязчивым" ("intrusive") списком, поскольку использование объекта в списке "навязывает" ему тип этого объекта. kamillxiii 06.05.14 в 14:12 Второй вид связанного списка называется "интрузивным", потому что использование объекта в списке вторгается в его определение. IngaJolly 01.09.14 в 17:31 |
+1 | |
|
Это делает такие списки менее гибкими, но, как мы видели, более эффективными. kamillxiii 06.05.14 в 14:13 Интрузивные списки менее гибкие, но, как мы видели, более эффективные. IngaJolly 01.09.14 в 17:41 |
||
|
Они распространены в таких местах, как ядро Linux, где этот компромисс сильно ощутим. kamillxiii 06.05.14 в 14:14 Они распространены в таких местах, как ядро Linux, где этот компромисс имеет смысл. IngaJolly 01.09.14 в 17:43 |
||
|
Способ избежания динамического создания прост: так как все узлы одного типа и размера, вы заранее создаёте Пул Объектов (Object Pool) для них. kamillxiii 06.05.14 в 14:16 Избежать динамического выделения просто: так как все узлы имеют одинаковый размер и тип, можно заранее выделить место под "Объектный пул" (Object Pool) из них. IngaJolly 01.09.14 в 17:46 |
+1 | |
|
Это дает вам фиксированное количество узлов списка, и по мере надобности вы можете снова и снова использовать их не производя реального выделения памяти. kamillxiii 06.05.14 в 14:24 Получается пачка узлов списка фиксированного размера, которую можно использовать, в том числе повторно, не трогая реальный распределитель памяти. IngaJolly 01.09.14 в 17:58 |
||
|
Оставшиеся Проблемы kamillxiii 06.05.14 в 14:25 Оставшиеся проблемы IngaJolly 01.09.14 в 17:59 |
||
|
Я думаю, мы прогнали из этого паттерна те две страшилки, которые пугали людей. kamillxiii 06.05.14 в 14:30 Думаю, мы прогнали двух главных монстров, пугающих людей в данном паттерне. IngaJolly 01.09.14 в 18:34 |
||
|
И как мы видим, паттерн прост, быстр и может легко подстраиваться под стиль управления памятью. kamillxiii 06.05.14 в 14:33 Как видно, паттерн простой, быстрый, его можно настроить для прекрасной работы с управлением памятью. IngaJolly 01.09.14 в 18:42 |
||
|
Но значит ли это, что вы постоянно должны использовать наблюдателей? kamillxiii 06.05.14 в 14:36 Но значит ли это, что нужно использовать наблюдателей все время? IngaJolly 01.09.14 в 18:43 |
||
|
Это уже другой вопрос. kamillxiii 06.05.14 в 14:37 |
