-
-
Save maplemap/d9ab8ad35e263eec9164030ffcbf0a0c to your computer and use it in GitHub Desktop.
[JS ES6 Паттерн СОСТОЯНИЕ (state)] #Паттерны #ООП #ES6 #js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* ПАТТЕРН СОСТОЯНИЕ (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