Skip to content

Proxy Design Pattern

Video Lecture

Section Video Links
Proxy Pattern Proxy Proxy Pattern 
Proxy Use Case Proxy Use Case Proxy Use Case 

Overview

...Refer to Book or Videos for extra content.

Terminology

...Refer to Book or Videos for extra content.

Proxy UML Diagram

Proxy Pattern UML Diagram

Source Code

./src/proxy/proxy-concept.ts

// A Proxy Concept Example

interface ISubject {
    // An interface implemented by both the Proxy and Real Subject
    request(): void
    // A method to implement
}

class RealSubject implements ISubject {
    // The actual real object that the proxy is representing

    enormousData: number[]

    constructor() {
        // hypothetically enormous amounts of data
        this.enormousData = [1, 2, 3]
    }

    request() {
        return this.enormousData
    }
}

class ProxySubject implements ISubject {
    // In this case the proxy will act as a cache for
    // `enormous_data` and only populate the enormous_data when it
    // is actually necessary

    enormousData: number[]
    realSubject: RealSubject

    constructor() {
        this.enormousData = []
        this.realSubject = new RealSubject()
    }
    request() {
        // Using the proxy as a cache, and loading data into it only if
        // it is needed
        if (this.enormousData.length === 0) {
            console.log('pulling data from RealSubject')
            this.enormousData = this.realSubject.request()
            return this.enormousData
        }
        console.log('pulling data from Proxy cache')
        return this.enormousData
    }
}

// The Client
const PROXY_SUBJECT = new ProxySubject()
// Use the Subject. First time it will load the enormous amounts of data
console.log(PROXY_SUBJECT.request())
// Use the Subject again, but this time it retrieves it from the local cache
console.log(PROXY_SUBJECT.request())

Output

node ./dist/proxy/proxy-concept.js
pulling data from RealSubject
[ 1, 2, 3 ]
pulling data from Proxy cache
[ 1, 2, 3 ]

Proxy Use Case

...Refer to Book or Videos for extra content.

Example UML Diagram

Proxy Use Case Example

Source Code

./src/proxy/client.ts

import Lion from './lion'

const PROTEUS = new Lion()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()
PROTEUS.tellMeTheFuture()
PROTEUS.tellMeYourForm()

./src/proxy/iproteus.ts

// The Proteus Interface
export default interface IProteus {
    // A Greek mythological character that can change to many forms

    tellMeTheFuture(): void
    // Proteus will change form rather than tell you the future

    tellMeYourForm(): void
    // The form of Proteus is elusive like the sea
}

./src/proxy/lion.ts

import IProteus from './iproteus'
import Leopard from './leopard'
import Serpent from './serpent'

export default class Lion implements IProteus {
    // Proteus in the form of a Lion

    name = 'Lion'

    tellMeTheFuture(): void {
        // Proteus will change to something random
        if (Math.floor(Math.random() * 2)) {
            Object.assign(this, new Serpent())
            this.tellMeTheFuture = Serpent.prototype.tellMeTheFuture
            this.tellMeYourForm = Serpent.prototype.tellMeYourForm
        } else {
            Object.assign(this, new Leopard())
            this.tellMeTheFuture = Leopard.prototype.tellMeTheFuture
            this.tellMeYourForm = Leopard.prototype.tellMeYourForm
        }
    }

    tellMeYourForm(): void {
        console.log(`I am the form of ${this.name}`)
    }
}

./src/proxy/serpent.ts

import IProteus from './iproteus'
import Leopard from './leopard'
import Lion from './lion'

export default class Serpent implements IProteus {
    // Proteus in the form of a Serpent

    name = 'Serpent'

    tellMeTheFuture(): void {
        // Proteus will change to something random
        if (Math.floor(Math.random() * 2)) {
            Object.assign(this, new Leopard())
            this.tellMeTheFuture = Leopard.prototype.tellMeTheFuture
            this.tellMeYourForm = Leopard.prototype.tellMeYourForm
        } else {
            Object.assign(this, new Lion())
            this.tellMeTheFuture = Lion.prototype.tellMeTheFuture
            this.tellMeYourForm = Lion.prototype.tellMeYourForm
        }
    }

    tellMeYourForm(): void {
        console.log(`I am the form of ${this.name}`)
    }
}

./src/proxy/leopard.ts

import IProteus from './iproteus'
import Lion from './lion'
import Serpent from './serpent'

export default class Leopard implements IProteus {
    // Proteus in the form of a Leopard

    name = 'Leopard'

    tellMeTheFuture(): void {
        // Proteus will change to something random
        if (Math.floor(Math.random() * 2)) {
            Object.assign(this, new Lion())
            this.tellMeTheFuture = Lion.prototype.tellMeTheFuture
            this.tellMeYourForm = Lion.prototype.tellMeYourForm
        } else {
            Object.assign(this, new Serpent())
            this.tellMeTheFuture = Serpent.prototype.tellMeTheFuture
            this.tellMeYourForm = Serpent.prototype.tellMeYourForm
        }
    }

    tellMeYourForm(): void {
        console.log(`I am the form of ${this.name}`)
    }
}

Output

node ./dist/proxy/client.js
I am the form of Lion
I am the form of Serpent
I am the form of Lion
I am the form of Serpent
I am the form of Leopard
I am the form of Lion
I am the form of Leopard

Summary

...Refer to Book or Videos for extra content.