История изменений
Исправление
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())