...

/

Proxy Pattern: Techniques for Implementing Proxies (II)

Proxy Pattern: Techniques for Implementing Proxies (II)

Learn how to create a proxy object using object augmentation and the ES2015 Proxy helper.

Object augmentation

Object augmentation (or monkey patching) is probably the simplest and most common way of proxying just a few methods of an object. It involves modifying the subject directly by replacing a method with its proxied implementation.

In the context of our calculator example, this could be done as follows:

Press + to interact
class StackCalculator {
constructor () {
this.stack = []
}
putValue (value) {
this.stack.push(value)
}
getValue () {
return this.stack.pop()
}
peekValue () {
return this.stack[this.stack.length - 1]
}
clear () {
this.stack = []
}
divide () {
const divisor = this.getValue()
const dividend = this.getValue()
const result = dividend / divisor
this.putValue(result)
return result
}
multiply () {
const multiplicand = this.getValue()
const multiplier = this.getValue()
const result = multiplier * multiplicand
this.putValue(result)
return result
}
}
function patchToSafeCalculator (calculator) {
const divideOrig = calculator.divide
calculator.divide = () => {
// additional validation logic
const divisor = calculator.peekValue()
if (divisor === 0) {
throw Error('Division by 0')
}
// if valid delegates to the subject
return divideOrig.apply(calculator)
}
return calculator
}
const calculator = new StackCalculator()
const safeCalculator = patchToSafeCalculator(calculator)
calculator.putValue(3)
calculator.putValue(2)
console.log(calculator.multiply()) // 3*2 = 6
safeCalculator.putValue(2)
console.log(safeCalculator.multiply()) // 6*2 = 12
// calculator.putValue(0)
// console.log(calculator.divide()) // 12/0 -> Error('Division by 0')
safeCalculator.clear()
safeCalculator.putValue(4)
safeCalculator.putValue(0)
console.log(safeCalculator.divide()) // 4/0 -> Error('Division by 0')

This technique is definitely convenient when we need to proxy only one or a few methods. Notice that we don’t have to reimplement the multiply() method and all the other delegated methods here.

Unfortunately, simplicity comes at the cost of having to mutate the subject object directly, which can be dangerous.

Note: Mutations should be avoided at all costs when the subject is shared with other parts of the codebase. In fact, “monkey patching” the subject might create undesirable side effects that affect other components of our application. Use this technique only when the subject exists in a controlled context or in a private scope. If we want to appreciate why "monkey patching" is a dangerous practice, we could try to invoke a division by zero in the original calculator instance. If we do so, we’ll see that the original instance will now throw an error rather than returning Infinity. The original behavior has been altered, and this might have unexpected effects on other parts of the application.

In the next section, we’ll explore the built-in Proxy object, which is a powerful alternative for implementing the Proxy pattern and more.

The built-in Proxy object

The ES2015 specification introduced a native way to create powerful proxy objects.

We’re talking about the ES2015 ...