Гарне питання! Перш ніж перейти до конкретних питань, які ви задали, я скажу: не варто недооцінювати силу простоти. Тенпн прав. Майте на увазі, що все, що ви намагаєтеся зробити з цими підходами, - це знайти елегантний спосіб відкласти функціональний виклик або від'єднати абонента від виклику. Я можу порекомендувати судові процедури як напрочуд інтуїтивно зрозумілий спосіб полегшити деякі з цих проблем, але це трохи поза темою. Іноді вам краще просто викликати функцію і жити з тим, що сутність A з'єднана безпосередньо з сутністю B. Див. YAGNI.
З цього приводу я використовував і задоволений моделлю сигнал / слот у поєднанні з простою передачею повідомлення. Я використовував його в C ++ та Lua для досить вдалого заголовку iPhone, який мав дуже щільний графік.
Що стосується випадку сигналу / слота, якщо я хочу, щоб об'єкт A зробив щось у відповідь на те, що зробив об'єкт B (наприклад, розблокувати двері, коли щось помирає), я можу мати суб'єкт А підписатися безпосередньо на смерть суб'єкта В. Або, можливо, суб'єкт А підписався на кожну з груп сутностей, збільшивши лічильник на кожну розстріляну подію та відчинивши двері після того, як N з них загинуло. Крім того, "група сутностей" і "N з них", як правило, є дизайнером, визначеним у даних рівня. (Вбік, це одна область, де дійсно можуть світитися супроводи, наприклад, WaitForMultiple ("Помирає", entA, entB, entC); door.Unlock ();)
Але це може стати громіздким, коли мова йде про реакції, які щільно поєднані з кодом C ++, або по суті ефемерними ігровими подіями: нанесення шкоди, перезавантаження зброї, налагодження, ігровий AI-зворотний зв'язок на основі локації. Тут передача повідомлень може заповнити прогалини. По суті, це зводиться до чогось типу, "скажіть усім суб'єктам в цій області отримати пошкодження за 3 секунди" або "щоразу, коли ви завершите фізику, щоб з'ясувати, хто я стріляв, скажіть їм виконувати цю функцію сценарію". Важко зрозуміти, як це зробити красиво, використовуючи публікацію / підписку або сигнал / слот.
Це легко може бути надмірним (порівняно з прикладом tenpn). Це також може бути неефективним здуттям, якщо у вас багато дій. Але, незважаючи на свої недоліки, ці "повідомлення та події" дуже добре підходять до сценарію ігрового коду (наприклад, у Луа). Код сценарію може визначати та реагувати на власні повідомлення та події без коду С ++. І код скрипту може легко надсилати повідомлення, які викликають код C ++, наприклад, зміна рівнів, відтворення звуків або навіть просто надання зброї встановити, скільки шкоди завдає повідомлення TakeDamage. Це врятувало мені багато часу, тому що мені не довелося постійно дурити з луабіндом. І це дозволило мені зберігати весь свій luabind код в одному місці, тому що його було не так багато. При правильному з'єднанні,
Крім того, мій досвід використання справи №2 полягає в тому, що вам краще поводитися з ним як з подією в іншому напрямку. Замість того, щоб запитувати про стан здоров’я суб'єкта господарювання, скасовуйте подію / надсилайте повідомлення щоразу, коли стан здоров'я змінює суттєві зміни.
Що стосується інтерфейсів, то btw, я закінчив три класи, щоб реалізувати все це: EventHost, EventClient та MessageClient. EventHosts створює слоти, EventClients підписуються / підключаються до них, а MessageClients асоціюють делегата з повідомленням. Зауважте, що ціль делегата MessageClient не обов'язково повинен бути тим самим об'єктом, який належить асоціації. Іншими словами, MessageClients можуть існувати виключно для пересилання повідомлень на інші об'єкти. FWIW, метафора хост / клієнт начебто недоречна. Джерело / раковина можуть бути кращими поняттями.
Вибачте, я якось туди проскочив. Це моя перша відповідь :) Сподіваюся, це мало сенс.