Elegant Objects

Работы по библиотеке Patron вдохновлены двумя книгами: Elegant Objects и Object Thinking

В этом разделе сделаем пример кода по расчету простой арифметической формулы с возможностью изменять переменные и одна из переменных будет таймером.

 

Результат 1. Вычисление на лету

( + ? ) * = ??

Листинг 1.

import {
  Guest,
  Source,
  Patron,
  SourceAll,
  GuestCast,
  GuestDisposable,
} from "patron-oop";
import { Text, Input } from "patron-components";

// Переместил клиентский код наверх,
// чтобы не крутить до самой интересной части.
window.numberTimer = new NumberFromTimer();
const numberInput1 = new NumberFromInput(".input-1");
const numberInput2 = new NumberFromInput(".input-2");
const result = new Multiplication(
  new Addition(numberInput1, numberTimer),
  numberInput2
);
numberTimer.start();
numberTimer.number(
  new Patron(
    new GuestDisposable(
      new Text(".eo-counter"),
      disposeIfNoSelector(".eo-counter")
    )
  )
);
result.number(
  new Patron(
    new GuestDisposable(
      new Text(".eo-result"),
      disposeIfNoSelector(".eo-result")
    )
  )
);

class NumberFromTimer {
  timerHead = null;

  constructor() {
    this.source = new Source(1);
  }

  number(guest) {
    this.source.value(guest);
  }

  start() {
    if (this.timerHead) {
      return;
    }
    const repeat = () => {
      this.source.value((value) => {
        this.timerHead = setTimeout(() => {
          this.source.give(value + 1);
          repeat();
          if (!this.source.pool().size()) {
            this.stop();
          }
        }, 1000);
      });
    };
    repeat();
  }

  stop() {
    clearTimeout(this.timerHead);
    this.timerHead = null;
  }

  reset() {
    this.stop();
    this.source.give(1);
    this.start();
  }
}

class NumberFromInput {
  constructor(selector) {
    this.source = new Source(1);
    this.input = new Input(this.source, selector);
  }

  number(guest) {
    this.source.value(
      new GuestCast(guest, (value) => {
        guest.give(+value);
      })
    );
  }
}

class Addition {
  constructor(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
  }

  number(guest) {
    const all = new SourceAll();
    this.num1.number(new GuestCast(guest, all.guestKey("n1")));
    this.num2.number(new GuestCast(guest, all.guestKey("n2")));
    all.value(
      new GuestCast(guest, ({ n1, n2 }) => {
        guest.give(n1 + n2);
      })
    );
  }
}

class Multiplication {
  constructor(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
  }

  number(guest) {
    const all = new SourceAll();
    this.num1.number(new GuestCast(guest, all.guestKey("n1")));
    this.num2.number(new GuestCast(guest, all.guestKey("n2")));
    all.value(
      new GuestCast(guest, ({ n1, n2 }) => {
        guest.give(n1 * n2);
      })
    );
  }
}

const disposeIfNoSelector = (selector) => () =>
  !document.querySelector(selector);