Страницы

Поиск по вопросам

среда, 18 декабря 2019 г.

Конечный автомат

#javascript #инспекция_кода


Набросал пример исходя из описания алгоритма. Хочу услышать замечания, что стоило
бы изменить в этом коде:



// https://en.wikipedia.org/wiki/Finite-state_machine
// https://en.wikipedia.org/wiki/Event-driven_finite-state_machine
class FSM {
  constructor(transitions = []) {
    this.transitions = new Map();
    for (let {
        from,
        event,
        to,
        action
      } of transitions) {
      this.addTransition(from, event, to, action);
    }
    this.currentState = transitions.length ? transitions[0].from : null;
  }

  addTransition(from, event, to, action) {
    let events = this.transitions.get(from);
    if (!events) {
      events = new Map();
      this.transitions.set(from, events);
    }
    events.set(event, {
      to,
      action
    });
  }

  emit(event, ...args) {
    const events = this.transitions.get(this.currentState);
    if (events) {
      const obj = events.get(event);
      if (obj) {
        this.currentState = obj.to;
        obj.action.apply(this, args);
      }
    }
  }
}


const turnstile = new FSM([{
    from: 'locked',
    event: 'coin',
    to: 'unlocked',
    action: () => {
      console.log('Турникет разблокирован, и посетитель может пройти.');
    }
  },
  {
    from: 'locked',
    event: 'push',
    to: 'locked',
    action: () => {
      console.log('Посетитель толкает турникет, но тот заблокирован.');
    }
  },
  {
    from: 'unlocked',
    event: 'coin',
    to: 'unlocked',
    action: () => {
      console.log('Посетитель опускает еще одну монету в турникет, состояние не меняется.');
    }
  },
  {
    from: 'unlocked',
    event: 'push',
    to: 'locked',
    action: () => {
      console.log('Как только посетитель проходит, турникет блокируется.');
    }
  },
]);

turnstile.emit('push');
turnstile.emit('coin');
turnstile.emit('coin');
turnstile.emit('push');
turnstile.emit('push');




Вывод:

Посетитель толкает турникет, но тот заблокирован.
Турникет разблокирован, и посетитель может пройти.
Посетитель опускает еще одну монету в турникет, состояние не меняется.
Как только посетитель проходит, турникет блокируется.
Посетитель толкает турникет, но тот заблокирован.

    


Ответы

Ответ 1



просто ещё один способ: class Au { constructor(States, Symbols, Table, currentState = States[Object.keys(States)[0]]) { this.States = States; this.Symbols = Symbols; this.Table = Table; this.currentState = currentState; ch(States, Symbols); info(States, Symbols, Table); } emit(_Symbol, ..._args) { let qqw = this.Table[this.currentState + _Symbol]; let state = null; if (qqw) { if (qqw[0]) this.currentState = qqw[0]; if (qqw[1]) qqw[1].apply(null, _args); } } } const turnstile = (function() { const States = { locked: 1 << 0, unlocked: 1 << 1, }; const Symbols = { coin: 1 << 2, push: 1 << 3, }; const Table = { [States.locked + Symbols.coin]: [States.unlocked, () => console.log('Турникет разблокирован, и посетитель может пройти.')], [States.locked + Symbols.push]: [States.locked, () => console.log('Посетитель толкает турникет, но тот заблокирован.')], [States.unlocked + Symbols.coin]: [States.unlocked, () => console.log('Посетитель опускает еще одну монету в турникет, состояние не меняется.')], [States.unlocked + Symbols.push]: [States.locked, () => console.log('Как только посетитель проходит, турникет блокируется.')], }; return new Au(States, Symbols, Table); })(); turnstile.emit(turnstile.Symbols.push); turnstile.emit(turnstile.Symbols.coin); turnstile.emit(turnstile.Symbols.coin); turnstile.emit(turnstile.Symbols.push); turnstile.emit(turnstile.Symbols.push); // -- function ch(States, Symbols) { let a = Object.keys(States); let b = Object.keys(Symbols); let ch = new Set([...a, ...b]); if (ch.size !== (a.length + b.length)) { throw new Error('номера ключей States и Symbols совпадают'); } } function info(States, Symbols, Table) { let l = { 'количество возможных комбинаций': Object.keys(States).length * Object.keys(Symbols).length, 'текущее количество комбинаций': Object.keys(Table).length, }; Object.keys(l).forEach(_k => console.log(_k, l[_k])); } наверное, this не нужен obj.action.apply(this, args); считаю что повторяющийся код, во избежании ошибок, должен быть в функции или классе { from: 'locked', event: 'coin', to: 'unlocked', action: () => { console.log('Турникет разблокирован, и посетитель может пройти.'); } }

Комментариев нет:

Отправить комментарий