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:
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 / divisorthis.putValue(result)return result}multiply () {const multiplicand = this.getValue()const multiplier = this.getValue()const result = multiplier * multiplicandthis.putValue(result)return result}}function patchToSafeCalculator (calculator) {const divideOrig = calculator.dividecalculator.divide = () => {// additional validation logicconst divisor = calculator.peekValue()if (divisor === 0) {throw Error('Division by 0')}// if valid delegates to the subjectreturn 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 = 6safeCalculator.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 ...