How to apply command pattern in js

236 Views Asked by At

I have a calculator app and I'm trying to apply the command pattern

I have a fully working version

Please help me figure out how I should do

How do I use the command pattern in my code?

CalculatorCore.js

class CalculatorModel {
  constructor() {
    this.currentValue = ''
    this.result = ''
    this.register = []
    this.history = []
  }

  executedCommand(command) {
    this.currentValue = command.execute(this.currentValue)
    this.history.push({
      command: command.name,
      value: this.currentValue,
    })
  }

  inputDigit(digit) {
    if (isNaN(digit)) {
      throw new Error('Digit is not a number')
    }

    if (this.result !== '') {
      this.currentValue = ''
      this.result = ''
    }

    this.currentValue += digit
  }

  inputDecimal() {
    if (this.result !== '') {
      this.currentValue = ''
      this.result = ''
    }

    if (this.currentValue.indexOf('.') >= 0) {
      return
    }

    if (this.currentValue === '') {
      this.currentValue += '0.'
    } else {
      this.currentValue += '.'
    }
  }

  clear() {
    this.currentValue = ''
    this.result = ''
    this.register = []
  }

  clearAll() {
    this.currentValue = ''
    this.result = ''
    this.register = []
    this.history = []
  }

  delete() {
    if (this.currentValue === '') {
      return
    }

    this.currentValue = this.currentValue.slice(0, -1)
  }

  undo() {
    if (this.history.length === 0) {
      return
    }

    const lastCommand = this.history.pop()
    this.currentValue = lastCommand.value
  }

  getResult() {
    return this.result
  }

  add() {
    if (this.currentValue === '') {
      return
    }

    this.register.push(this.currentValue)
    this.register.push('+')
    this.currentValue = ''
  }

  subtract() {
    if (this.currentValue === '') {
      return
    }

    this.register.push(this.currentValue)
    this.register.push('-')
    this.currentValue = ''
  }

  multiply() {
    if (this.currentValue === '') {
      return
    }

    this.register.push(this.currentValue)
    this.register.push('*')
    this.currentValue = ''
  }

  divide() {
    if (this.currentValue === '') {
      return
    }

    this.register.push(this.currentValue)
    this.register.push('/')
    this.currentValue = ''
  }

  getHistory() {
    return this.history
  }

  getRegister() {
    return this.register
  }

  getCurrentValue() {
    return this.currentValue
  }

  equals() {
    if (this.currentValue === '') {
      return
    }

    this.register.push(this.currentValue)

    this.result = eval(this.register.join(''))

    this.history.push({
      expression: this.register.join(''),
      result: this.result,
    })

    this.register = []
    this.currentValue = this.result.toString()
  }

  toggleSign() {
    this.currentValue = this.currentValue * -1
  }
}

class AddCommand {
  constructor(value) {
    this.name = 'add'
    this.value = value
  }

  execute(currentValue) {
    return currentValue + this.value
  }

  undo() {
    return this.currentValue - this.value
  }
}

class SubtractCommand {
  constructor(value) {
    this.name = 'subtract'
    this.value = value
  }

  execute(currentValue) {
    return currentValue - this.value
  }

  undo() {
    return this.currentValue + this.value
  }
}

class MultiplyCommand {
  constructor(value) {
    this.name = 'multiply'
    this.value = value
  }

  execute(currentValue) {
    return currentValue * this.value
  }

  undo() {
    return this.currentValue / this.value
  }
}

class DivideCommand {
  constructor(value) {
    this.name = 'divide'
    this.value = value
  }

  execute(currentValue) {
    return currentValue / this.value
  }

  undo() {
    return this.currentValue * this.value
  }
}

class ClearCommand {
  constructor() {
    this.name = 'clear'

  }

  execute() {
    return ''
  }

  undo() {
    return this.currentValue
  }
}

class ClearAllCommand {
  constructor() {
    this.name = 'clearAll'
  }

  execute() {
    return ''
  }

  undo() {
    return this.currentValue
  }
}

class DeleteCommand {
  constructor() {
    this.name = 'delete'
  }

  execute(currentValue) {
    return currentValue.slice(0, -1)
  }

  undo() {
    return this.currentValue
  }
}

class ToggleSignCommand {
  constructor() {
    this.name = 'toggleSign'
  }

  execute(currentValue) {
    return currentValue * -1
  }

  undo() {
    return this.currentValue
  }
}

class EqualsCommand {
  constructor() {
    this.name = 'equals'
  }

  execute(currentValue) {
    return currentValue
  }

  undo() {
    return this.currentValue
  }
}

class UndoCommand {
  constructor() {
    this.name = 'undo'
  }

  execute(currentValue) {
    return currentValue
  }

  undo() {
    return this.currentValue
  }
}

export {
  CalculatorModel,
  AddCommand,
  SubtractCommand,
  MultiplyCommand,
  DivideCommand,
  ClearCommand,
  ClearAllCommand,
  DeleteCommand,
  ToggleSignCommand,
  EqualsCommand,
  UndoCommand,
}

Calculator.jsx

export class Calculator extends Component {
  constructor(props) {
    super(props)
    this.state = {
      isHistoryOpen: false,
      history: [],
      formula: [],
      input: '',
      result: '',
    }

    this.handleDigit = this.handleDigit.bind(this)
    this.handleClear = this.handleClear.bind(this)
    this.handleDelete = this.handleDelete.bind(this)
    this.handleToggleSign = this.handleToggleSign.bind(this)
    this.handleOperator = this.handleOperator.bind(this)
    this.handleDecimalPoint = this.handleDecimalPoint.bind(this)
    this.handleEqual = this.handleEqual.bind(this)
    this.handleHistoryClick = this.handleHistoryClick.bind(this)
  }

  handleDigit(number) {
    calculator.executedCommand(new AddCommand(number))

    this.setState(prevState => ({
      input: prevState.input + number,
      formula: prevState.formula.concat(number),
    }))
  }

  handleClear() {
    this.setState({
      input: '',
      formula: [],
      result: '',
    })
  }

  handleDelete() {
    this.setState(prevState => ({
      input: prevState.input.slice(0, -1),
    }))
  }

  handleToggleSign() {
    this.setState(prevState => ({
      input:
        prevState.input.charAt(0) === '-'
          ? prevState.input.slice(1)
          : '-' + prevState.input,
    }))
  }

  handleOperator(operator) {
    this.setState(prevState => ({
      input: prevState.input + operator,
    }))
  }

  handleDecimalPoint() {
    if (!this.state.input.includes('.')) {
      this.setState(prevState => ({
        input: prevState.input + '.',
      }))
    }
  }

  handleEqual() {
    this.setState(prevState => ({
      result: eval(prevState.input),
    }))
    this.setState(prevState => ({
      history: [
        ...prevState.history,
        {
          input: prevState.input,
          result: prevState.result,
        },
      ],
    }))
    this.setState({
      input: '',
    })
  }

  handleHistoryClick() {
    this.setState(prevState => ({
      isHistoryOpen: !prevState.isHistoryOpen,
    }))
  }

  render() {
    return (
      <Fragment>
        <MainContainer>
          <LeftSide>
            <ControlPanel onHistoryClick={this.handleHistoryClick} />
            <Display
              result={this.state.result}
              input={this.state.input}
              formula={this.state.formula}
            />
            <Keypad
              onDigit={this.handleDigit}
              onClear={this.handleClear}
              onDelete={this.handleDelete}
              onToggleSign={this.handleToggleSign}
              onOperator={this.handleOperator}
              onDecimalPoint={this.handleDecimalPoint}
              onEqual={this.handleEqual}
            />
          </LeftSide>
          {this.state.isHistoryOpen && (
            <History history={this.state.history} />
          )}
        </MainContainer>
      </Fragment>
    )
  }
}

I have read and studied the pattern, but how should I apply it to my application, I cannot yet understand and deal with it

0

There are 0 best solutions below