Подписка на событие и передача данных javascript

102
24 августа 2019, 19:50

Есть следующая задача.

Даны класс Rabbit и класс Hunter. Rabbit может менять свои координаты x и y. Нужно сделать так, чтобы при изменении координат охотники, созданные через конструктор вне зависимости от их количества могли получать эти координаты, то есть были подписаны на изменения в Rabbit. Код выглядит так:

'use strict';
class Rabbit {
  constructor(name) {
    this.name = name;
    this.x = 0;
    this.y = 0;
  }
  move() {
    this.x = (Math.random() * 100).toFixed(0);
    this.y = (Math.random() * 100).toFixed(0);
    console.log(this.x, this.y, this.name + ' ' + 'moved');
  }
}
class Hunter {
  constructor(name) {
    this.name = name;
  }
}
let rabbit = new Rabbit("Jonny");
rabbit.move();
let hunter1 = new Hunter("Ted");
let hunter2 = new Hunter("Billy");
let hunter3 = new Hunter("Greg");

Полагаю, что классу Hunter нужен какой-нибудь метод notification, а классу Rabbit передавался массив подписчиков, которым нужно передать данные, но как это реализовать, не пойму.

Answer 1

class Rabbit { 
  constructor(name) { 
    this.name = name; 
    this.x = 0; 
    this.y = 0; 
    this.handlersMove = []; 
  } 
 
  move() { 
    this.x = (Math.random() * 100).toFixed(0); 
    this.y = (Math.random() * 100).toFixed(0); 
    console.log(this.x, this.y, this.name + ' ' + 'moved'); 
    this.handlersMove.forEach(handler => handler(this)); 
  } 
} 
 
class Hunter { 
  constructor(name) { 
    this.name = name; 
  } 
   
  onGameMoves(game) { 
    console.log(`${this.name} sees that ${game.constructor.name} ${game.name} moved to (${game.x}, ${game.y}).`); 
  } 
} 
 
let rabbit = new Rabbit("Jonny"); 
 
let hunter1 = new Hunter("Ted"); 
rabbit.handlersMove.push(hunter1.onGameMoves.bind(hunter1)); 
let hunter2 = new Hunter("Billy"); 
let hunter3 = new Hunter("Greg"); 
rabbit.handlersMove.push(hunter3.onGameMoves.bind(hunter3)); 
 
rabbit.move();

Answer 2

Вы в своём вопросе на него же и ответили, воспользуйтесь шаблоном публикатор-подписчик.

Все это выглядит примерно так:

Где то в начале создаётся глобальный объект, назовём его broker который имеет 2 метода fire(отправить событие) и on(подписаться на событие)

let broker = new Broker();

Затем все Hunter при создании подписываются на событие rabbit-moved

broker.on("rabbit-moved", hunt)

Тут я предположил что у охотника есть метод hunt(eventContext) в котором находится код логики охоты

Когда произойдёт изменение координат какого либо Rabbit, то есть внутри вашего метода Rabbit.move() вы отправляете событие rabbit-moved

broker.fire("rabbit-moved", eventContext)

Вторым аргументом тут идёт объект, который будет содержать всю необходимую информацию об обработке этого события, в нашем случае это x и y наших кроликов.

Брокер отправляет это сообщение всем подписчикам,

topic - на картинке выше, это имя нашего события

Сам брокер может отличаться тяжестью случая, самая простая версия выглядит примерно так

class Broker { 
  constructor() { 
    // массивы подписчиков привязанные к каждому топику 
    this.subscribers = {}; 
  } 
 
  // метод подписки 
  on(topic, func) { 
    if (!this.subscribers[topic]) 
      this.subscribers[topic] = []; 
    this.subscribers[topic].push(func); 
  } 
 
  // метод оповещения подписчиков 
  fire(topic, data) { 
    if (this.subscribers[topic]) 
      this.subscribers[topic].forEach(l => l(data)); 
  } 
} 
    
// создаётся глобальный объект, который связывает публикаторов и подписчиков 
let broker = new Broker(); 
 
class Rabbit { 
  constructor(name) { 
    this.name = name; 
    this.x = 0; 
    this.y = 0; 
    this.handlersMove = []; 
  } 
 
  move() { 
    this.x = (Math.random() * 100).toFixed(0); 
    this.y = (Math.random() * 100).toFixed(0); 
    // все кролики в момент перемещение публикуют событие 
    broker.fire('rabbit-moved', this); 
  } 
} 
 
class Hunter { 
  constructor(name) { 
    this.name = name; 
    // все охотники подписаны на топик "rabbit-moved"  
    // и когда приходит данное событие вызывается метод hunt 
    broker.on('rabbit-moved', data => this.hunt(data)) 
  } 
 
  hunt(data) { 
    console.log(`Hunter ${this.name}: I saw ${data.name} at ${data.x}:${data.y}`); 
  } 
} 
 
// создаем 10 кроликов и 2 охотника 
let rabbits = Array(10).fill(0).map((e, i) => new Rabbit(`Rabbit ${i+1}`)); 
new Hunter("Tom") 
new Hunter("Max") 
 
 
function moveRandomRabbit() { 
  // перемещение случайного кролика в случайную точку 
  rabbits[Math.floor(Math.random() * rabbits.length)].move(); 
}
<button onclick="moveRandomRabbit()">move random rabbit</button>

READ ALSO
Конвертирование base64 строки в массив байт

Конвертирование base64 строки в массив байт

На страничке необходимо загрузить в input type file, а так же вывести эту картинку в imgА далее ajax запросом передать base64 строку на сервер и там перевести...

118
Как правильно оформить динамический manifest.json в PWA?

Как правильно оформить динамический manifest.json в PWA?

Нужно в аяксе после успешного ответа от сервера показывать кнопку для сохранения приложения на рабочий столСделал динамический манифест...

112
Уменьшение время подгрузки данных в Chosen

Уменьшение время подгрузки данных в Chosen

Что имею: n-ное количество переменных (500-2000), которые достаю из базы и передаю в нужный мне `, созданного при помощи плагина Chosen:

99
Не могу добавить кастомный класс кнопке на яндекс-картах под ИЕ11

Не могу добавить кастомный класс кнопке на яндекс-картах под ИЕ11

Я создаю кнопку на карте с помощью следующего кода:

100