Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

3 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. *
  3. * Реализация шаблона "издатель-подписчик"
  4. *
  5. */
  6. function Уведомитель()
  7. {
  8. function Подписка(id, отклик, уведомитель)
  9. {
  10. this.id = id;
  11. this.отклик = отклик;
  12. this.уведомитель = уведомитель;
  13. };
  14. this.уведомить = function()
  15. {
  16. // Попутно собираем подписки без отклика.
  17. var безотклика = [];
  18. for (var номер in this.подписки)
  19. {
  20. var подписка = this.подписки[номер];
  21. if (подписка.отклик)
  22. {
  23. подписка.отклик();
  24. }
  25. else
  26. {
  27. безотклика.push(подписка);
  28. }
  29. }
  30. // И удаляем их.
  31. if (безотклика.length)
  32. {
  33. this._удалитьПодпискиБезОтклика(безотклика);
  34. }
  35. };
  36. this.подписать = function(отклик)
  37. {
  38. var id = this._сгенерироватьUUID();
  39. var подписка = new Подписка(id, отклик, this);
  40. this.подписки.push(подписка);
  41. return подписка;
  42. };
  43. this.отписать = function(подписка)
  44. {
  45. подписка.отклик = null;
  46. };
  47. this._удалитьПодпискиБезОтклика = function(удалить)
  48. {
  49. var подписка = удалить.shift()
  50. while (подписка)
  51. {
  52. var индекс = this.подписки.indexOf(подписка);
  53. if (индекс !== -1)
  54. {
  55. this.подписки.splice(индекс, 1);
  56. }
  57. var подписка = удалить.shift()
  58. }
  59. };
  60. this._сгенерироватьUUID = function()
  61. {
  62. // https://stackoverflow.com/a/2117523
  63. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
  64. /[xy]/g,
  65. function(c)
  66. {
  67. var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
  68. return v.toString(16);
  69. }
  70. );
  71. };
  72. // Конструктор.
  73. this.подписки = [];
  74. }
  75. /*
  76. *
  77. * Связь событий и реакций в виде последовательности (череды)
  78. *
  79. */
  80. function Мир()
  81. {
  82. // Разобрать события и реакции, выраженные в тексте.
  83. this.разобрать = function(череда)
  84. {
  85. var соответствия = this._событияРеакции(череда);
  86. for (var событие in соответствия)
  87. {
  88. if (!(событие in this.события))
  89. {
  90. this.события[событие] = new Уведомитель();
  91. }
  92. var реакции = соответствия[событие];
  93. for (var номер in реакции)
  94. {
  95. const реакция = реакции[номер];
  96. const название = this._имяФункцииИзРеакции(реакция);
  97. const функция = eval(название);
  98. var тут = this;
  99. this.события[событие].подписать(function(){
  100. функция(тут);
  101. });
  102. }
  103. }
  104. };
  105. // Уведомить о событии при его наличии.
  106. this.уведомить = function(событие)
  107. {
  108. if (событие in this.события)
  109. {
  110. this.события[событие].уведомить();
  111. }
  112. };
  113. // Разобрать текст с событиями и реакциями, вернуть словарь их соответствия.
  114. this._событияРеакции = function(текст)
  115. {
  116. var соответствие = {};
  117. var элементы = текст.split("\n");
  118. var имяСобытия = null;
  119. for (var номер in элементы)
  120. {
  121. var элемент = элементы[номер];
  122. // Пропускаем комментарии.
  123. if (элемент.charAt(0) == "#")
  124. {
  125. continue;
  126. }
  127. var имя = элемент.trim();
  128. // Пропускаем пустые строки.
  129. if (!имя.length)
  130. {
  131. continue;
  132. }
  133. // Событие.
  134. if (имя == элемент)
  135. {
  136. if (!(имя in соответствие))
  137. {
  138. имяСобытия = имя;
  139. соответствие[имя] = [];
  140. }
  141. }
  142. // Реакция.
  143. else
  144. {
  145. соответствие[имяСобытия].push(имя);
  146. }
  147. }
  148. return соответствие;
  149. };
  150. // Преобразовать имя реакции в название функции.
  151. this._имяФункцииИзРеакции = function(реакция)
  152. {
  153. var имя = "";
  154. var части = реакция.split(" ");
  155. for (var номер in части)
  156. {
  157. var часть = части[номер];
  158. имя += часть.charAt(0).toUpperCase() + часть.slice(1);
  159. }
  160. return имя;
  161. };
  162. // Конструктор.
  163. this.события = {};
  164. }
  165. /*
  166. *
  167. * Создание глобального мира.
  168. *
  169. */
  170. мир = new Мир();