LINUX.ORG.RU

История изменений

Исправление InterVi, (текущая версия) :

Простая демонстрация паттерна для JS, которую легко применять в своих проектах:

class IntValue {
  _intValue

  /**
   *
   * @param {Number} value int value
   * @throws {Error} if value in not int
   */
  constructor(value) {
    if (!Number.isInteger(value)) {
      throw new Error(`${value} is not int`)
    }
    this._intValue = value
  }

  /**
   * get int value
   * @returns {Number} int value
   */
  getInt() {
    return this._intValue
  }
}

/**
 *
 * @param {function} target
 * @returns {IntValue}
 * @throws {Error} if return is not IntValue
 */
function intValueDecorator(target) {
  return function(...args) {
    const result = target(...args)
    if (!Object.prototype.hasOwnProperty.call(result, '_intValue')) {
      throw new Error('return is not type of IntValue')
    }
    return result
  }
}

// example usage

const multiple = intValueDecorator(function(a) {
  return new IntValue(a.getInt() *2)
})

console.log(multiple(new IntValue(2)).getInt())

Входящие аргументы примитивно проверяютя вызовом getInt(), а возвращаемый результат контролируется декоратором intValueDecorator.

Продвинутая демонстрация как можно написать библиотеку:

// in real world it must be use singleton
let overhead = true

class IntOptional {
  _success
  _error
  _intValue

  /**
   *
   * @param {Number} value int number
   * @param {Error|null} error pass Error obj if not success
   */
  constructor(value, error) {
    this._success = false
    this._error = null
    this._intValue = 0
    if (error) {
      this._error = error
    }
    this._intValue = value
    if (overhead) {
      if (!Number.isInteger(this._intValue)) {
        this._error = new Error('value is not int')
      } else if (!error) {
        this._success = true
      }
    } else if (!error) {
      this._success = true
    }
  }

  /**
   * get int value
   * @returns {Number} int value
   * @throws {Error} if not success or wrong type value
   */
  value() {
    if (overhead) {
      if (this._error) {
        throw this._error
      }
      if (!Number.isInteger(this._intValue)) {
        throw new Error('value is not int')
      }
    }
    return this._intValue
  }

  /**
   * check for error on wrong type value
   * @returns {boolean} true if success and false if not (error or wrong type)
   */
  isSuccess() {
    return this._success
  }

  /**
   * get error
   * @returns {Error|null} get error
   */
  error() {
    return this._error
  }

  /**
   * for pretty print
   * @returns {string}
   */
  toString() {
    return this.isSuccess() ? `IntValue: ${this.value()}` : 'IntValue: fail'
  }

  /**
   * check value is {IntOptional} instance of not
   * @param {*} value for checking
   * @returns {boolean}
   */
  static isIntOptional(value) {
    if (!overhead) return true
    if (typeof value !== 'object') return false
    for (const key of [ 'value', 'isSuccess', 'error' ]) {
      if (typeof value[key] !== 'function') {
        return false
      }
    }
    //if (!Number.isInteger(value.value())) return false
    if (typeof value.isSuccess() !== 'boolean') return false
    if (typeof value.error() !== 'object') return false
    return true
  }

  /**
   * check success IntOptional obg
   * @param {*} value
   * @returns {boolean} if value is IntOptional will return result of value.isSuccess()
   */
  static success(value) {
    if (!IntOptional.isIntOptional(value)) return false
    return value.isSuccess()
  }
}

/**
 * decorate function: all of args and return must be IntOptional,
 * will return only {IntOptional} and not throw exceptions
 * @param {function} target function for decorate
 * @returns {IntOptional}
 */
function intOptionalDecorator(target) {
  return function(...args) {
    try {
      for (const arg of args) {
        if (!IntOptional.isIntOptional(arg)) {
          return new IntOptional(0, new Error(`"${arg}" is not IntOptional`))
        }
      }
      const result = target(...args)
      if (IntOptional.isIntOptional(result)) {
        return result
      } else {
        return new IntOptional(0, new Error('a is not IntOptional'))
      }
    } catch (err) {
      return new IntOptional(0, err)
    }
  }
}

// example usage

const plus = intOptionalDecorator(function(a) {
  return new IntOptional(a.value() + 1)
})

console.log('plus example')
console.log(plus(new IntOptional(1)).toString())
console.log(plus('blahblah').toString())
console.log(plus(new IntOptional(1.1)).toString())
console.log(plus(new IntOptional('blahblah')).toString())

function minus(a) {
  if (!IntOptional.success(a)) {
    return new IntOptional(0, new Error('a is not IntOptional'))
  }
  return new IntOptional(a.value() - 1)
}

console.log('minus example')
console.log(minus(new IntOptional(2)).toString())
console.log(minus('blahblah').toString())
console.log(minus(new IntOptional(1.1)).toString())
console.log(minus(new IntOptional('blahblah')).toString())

Исходная версия InterVi, :

Простая демонстрация Optional паттерна для JS, которую легко применять в своих проектах:

class IntValue {
  _intValue

  /**
   *
   * @param {Number} value int value
   * @throws {Error} if value in not int
   */
  constructor(value) {
    if (!Number.isInteger(value)) {
      throw new Error(`${value} is not int`)
    }
    this._intValue = value
  }

  /**
   * get int value
   * @returns {Number} int value
   */
  getInt() {
    return this._intValue
  }
}

/**
 *
 * @param {function} target
 * @returns {IntValue}
 * @throws {Error} if return is not IntValue
 */
function intValueDecorator(target) {
  return function(...args) {
    const result = target(...args)
    if (!Object.prototype.hasOwnProperty.call(result, '_intValue')) {
      throw new Error('return is not type of IntValue')
    }
    return result
  }
}

// example usage

const multiple = intValueDecorator(function(a) {
  return new IntValue(a.getInt() *2)
})

console.log(multiple(new IntValue(2)).getInt())

Входящие аргументы примитивно проверяютя вызовом getInt(), а возвращаемый результат контролируется декоратором intValueDecorator.

Продвинутая демонстрация как можно написать библиотеку:

// in real world it must be use singleton
let overhead = true

class IntOptional {
  _success
  _error
  _intValue

  /**
   *
   * @param {Number} value int number
   * @param {Error|null} error pass Error obj if not success
   */
  constructor(value, error) {
    this._success = false
    this._error = null
    this._intValue = 0
    if (error) {
      this._error = error
    }
    this._intValue = value
    if (overhead) {
      if (!Number.isInteger(this._intValue)) {
        this._error = new Error('value is not int')
      } else if (!error) {
        this._success = true
      }
    } else if (!error) {
      this._success = true
    }
  }

  /**
   * get int value
   * @returns {Number} int value
   * @throws {Error} if not success or wrong type value
   */
  value() {
    if (overhead) {
      if (this._error) {
        throw this._error
      }
      if (!Number.isInteger(this._intValue)) {
        throw new Error('value is not int')
      }
    }
    return this._intValue
  }

  /**
   * check for error on wrong type value
   * @returns {boolean} true if success and false if not (error or wrong type)
   */
  isSuccess() {
    return this._success
  }

  /**
   * get error
   * @returns {Error|null} get error
   */
  error() {
    return this._error
  }

  /**
   * for pretty print
   * @returns {string}
   */
  toString() {
    return this.isSuccess() ? `IntValue: ${this.value()}` : 'IntValue: fail'
  }

  /**
   * check value is {IntOptional} instance of not
   * @param {*} value for checking
   * @returns {boolean}
   */
  static isIntOptional(value) {
    if (!overhead) return true
    if (typeof value !== 'object') return false
    for (const key of [ 'value', 'isSuccess', 'error' ]) {
      if (typeof value[key] !== 'function') {
        return false
      }
    }
    //if (!Number.isInteger(value.value())) return false
    if (typeof value.isSuccess() !== 'boolean') return false
    if (typeof value.error() !== 'object') return false
    return true
  }

  /**
   * check success IntOptional obg
   * @param {*} value
   * @returns {boolean} if value is IntOptional will return result of value.isSuccess()
   */
  static success(value) {
    if (!IntOptional.isIntOptional(value)) return false
    return value.isSuccess()
  }
}

/**
 * decorate function: all of args and return must be IntOptional,
 * will return only {IntOptional} and not throw exceptions
 * @param {function} target function for decorate
 * @returns {IntOptional}
 */
function intOptionalDecorator(target) {
  return function(...args) {
    try {
      for (const arg of args) {
        if (!IntOptional.isIntOptional(arg)) {
          return new IntOptional(0, new Error(`"${arg}" is not IntOptional`))
        }
      }
      const result = target(...args)
      if (IntOptional.isIntOptional(result)) {
        return result
      } else {
        return new IntOptional(0, new Error('a is not IntOptional'))
      }
    } catch (err) {
      return new IntOptional(0, err)
    }
  }
}

// example usage

const plus = intOptionalDecorator(function(a) {
  return new IntOptional(a.value() + 1)
})

console.log('plus example')
console.log(plus(new IntOptional(1)).toString())
console.log(plus('blahblah').toString())
console.log(plus(new IntOptional(1.1)).toString())
console.log(plus(new IntOptional('blahblah')).toString())

function minus(a) {
  if (!IntOptional.success(a)) {
    return new IntOptional(0, new Error('a is not IntOptional'))
  }
  return new IntOptional(a.value() - 1)
}

console.log('minus example')
console.log(minus(new IntOptional(2)).toString())
console.log(minus('blahblah').toString())
console.log(minus(new IntOptional(1.1)).toString())
console.log(minus(new IntOptional('blahblah')).toString())