Skip to content

Instantly share code, notes, and snippets.

@DmitriiNazimov
Last active April 25, 2024 15:24
Show Gist options
  • Save DmitriiNazimov/e9cee44599e7394aa84f13885664e3f1 to your computer and use it in GitHub Desktop.
Save DmitriiNazimov/e9cee44599e7394aa84f13885664e3f1 to your computer and use it in GitHub Desktop.
[JS ES6 Паттерн СОСТОЯНИЕ (state)] #Паттерны #ООП #ES6 #js
/**
*
* ПАТТЕРН СОСТОЯНИЕ (state)
*
* Паттерн Состояние управляет изменением поведения объекта при изменении его внутреннего состояния.
* Внешне это выглядит так, словно объект меняет свой класс.
*
* Основная идея в том, что программа может находиться в одном из нескольких состояний, которые всё время сменяют друг
* друга. Набор этих состояний, а также переходов между ними, предопределён и конечен. Находясь в разных состояниях,
* программа может по-разному реагировать на одни и те же события, которые происходят с ней.
*/
// Вариант с последовательным перебором состояний, как меняется состояние утро-день-вечер-ночь
class TrafficLight {
constructor() {
this.states = [new GreenLight(), new RedLight(), new YellowLight()];
this.current = this.states[0];
}
change() {
const totalStates = this.states.length;
let currentIndex = this.states.findIndex(light => light === this.current);
if (currentIndex + 1 < totalStates) this.current = this.states[currentIndex + 1];
else this.current = this.states[0];
}
sign() {
return this.current.sign();
}
}
class Light {
constructor(light) {
this.light = light;
}
}
class RedLight extends Light {
constructor() {
super('red');
}
sign() {
return 'STOP';
}
}
class YellowLight extends Light {
constructor() {
super('yellow');
}
sign() {
return 'STEADY';
}
}
class GreenLight extends Light {
constructor() {
super('green');
}
sign() {
return 'GO';
}
}
// usage
const trafficLight = new TrafficLight();
console.log(trafficLight.sign()); // 'GO'
trafficLight.change();
console.log(trafficLight.sign()); // 'STOP'
trafficLight.change();
console.log(trafficLight.sign()); // 'STEADY'
trafficLight.change();
console.log(trafficLight.sign()); // 'GO'
trafficLight.change();
console.log(trafficLight.sign()); // 'STOP'
// Вариант с указанием клиентом на нужное состояние
const upperCase = inputString => inputString.toUpperCase()
const lowerCase = inputString => inputString.toLowerCase()
const defaultTransform = inputString => inputString
class TextEditor {
constructor(transform) {
this._transform = transform
}
setTransform(transform) {
this._transform = transform
}
type(words) {
console.log(this._transform(words))
}
}
const editor = new TextEditor(defaultTransform)
editor.type('First line')
editor.setTransform(upperCase)
editor.type('Second line')
editor.type('Third line')
editor.setTransform(lowerCase)
editor.type('Fourth line')
editor.type('Fifth line')
// First line
// SECOND LINE
// THIRD LINE
// fourth line
// fifth line
ЕЩЕ ОДИН ВАРИАНТ, ПОСЛОЖНЕЕ
class GumballMachine {
static gumballAmount;
static soldCounter = 0;
constructor(gumballNum) {
if (!gumballNum) {
throw new Error(`При создании ${this.constructor.name} не было указано изначальное количество шариков`);
}
GumballMachine.gumballAmount = gumballNum;
this.states = {noCoin: new NoCoin(), isCoin: new IsCoin(), gumballSold: new GumballSold(),
emptyMachine: new EmptyMachine()};
this.current = this.states.noCoin;
}
InsertCoin() {
this.current.InsertCoin(this);
}
ReturnCoin() {
this.current.ReturnCoin(this);
}
SellGumball() {
this.current.SellGumball(this);
}
AddGumball(num) {
GumballMachine.gumballAmount = num;
this.current = this.states.noCoin;
console.log('Жевачка добавлена в количестве: ' + num + ' шт.');
}
}
//Классы состояний
class GumballStates { //
InsertCoin() {
throw new Error(`В ${this.constructor.name} не описан метод InsertCoin()`);
}
ReturnCoin() {
throw new Error(`В ${this.constructor.name} не описан метод InsertCoin()`);
}
SellGumball() {
throw new Error(`В ${this.constructor.name} не описан метод InsertCoin()`);
}
}
//нет монетки
class NoCoin extends GumballStates {
InsertCoin(machine) {
console.log('Монетка вставлена');
machine.current = machine.states.isCoin;
}
ReturnCoin() {
console.error(`Нельзя вернуть монетку т.к. она не вставлена`);
}
SellGumball() {
console.error(`Нельзя продать жевачку т.к. не вставлена монетка`);
}
}
// есть монетка
class IsCoin extends GumballStates{
InsertCoin() {
console.error(`Нельзя вставить монетку т.к. она уже вставлена`);
}
ReturnCoin(machine) {
console.log('Монетка возвращена');
machine.current = machine.states.noCoin;
}
SellGumball() {
if (GumballMachine.gumballAmount > 0) {
console.log(`Жевачка успешно продана и выдана!`);
machine.current = machine.states.gumballSold;
GumballMachine.gumballAmount = GumballMachine.gumballAmount - 1;
GumballMachine.soldCounter += 1;
console.log(GumballMachine.soldCounter);
if (!(GumballMachine.soldCounter % 10)) { // если количество продаж кратно 10 - выдаем счастливую жвачку
console.log(`Счастливая жевачка успешно выдана! LUCKY MAN!!!`);
}
} else {
machine.current = machine.states.emptyMachine;
console.log('Извините, монетки не принимаются т.к. аппарат пуст');
console.log('Монетка возвращена');
}
}
}
// жевачка продана
class GumballSold extends GumballStates{
InsertCoin(machine) {
if (GumballMachine.gumballAmount > 0) {
machine.current = machine.states.isCoin;
console.log('Монетка вставлена');
} else {
machine.current = machine.states.emptyMachine;
console.log('Извините, монетки не принимаются т.к. аппарат пуст');
}
}
ReturnCoin() {
console.error('Нельзя вернуть монетку т.к. жевачка уже выдана');
}
SellGumball() {
console.error(`Нельзя продать жевачку т.к. она уже продана`);
}
}
//автомат пустой, жевачек нет
class EmptyMachine extends GumballStates{
InsertCoin() {
console.log('Извините, монетки не принимаются т.к. аппарат пуст');
}
ReturnCoin() {
console.error('Нельзя вернуть монетку т.к. монетка не вставлена');
}
SellGumball() {
console.error(`Нельзя продать жевачку т.к. она автомат пуст`);
}
}
// usage
const machine = new GumballMachine(1);
machine.InsertCoin();
machine.ReturnCoin();
machine.InsertCoin();
machine.SellGumball();
machine.InsertCoin();
machine.SellGumball();
machine.AddGumball(10);
machine.InsertCoin();
machine.SellGumball();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment