Skip to content

Instantly share code, notes, and snippets.

@Neo42
Last active January 17, 2022 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Neo42/f3e9beae4f57ed9e118a1ed2f59fa9f9 to your computer and use it in GitHub Desktop.
Save Neo42/f3e9beae4f57ed9e118a1ed2f59fa9f9 to your computer and use it in GitHub Desktop.
Design patterns in JavaScript
class OrderManager {
orders = new Set()
execute(command, ...args) {
return command.run(this.orders, ...args)
}
}
class Command {
constructor(steps) {
this.run = steps
}
}
function PlaceOrderCommand(order, id) {
return new Command((orders) => {
orders.add({id, order})
console.log(`You have successfully ordered ${order} (${id}).`)
})
}
function CancelOrderCommand(id) {
return new Command((orders) => {
orders.delete(id)
console.log(`You have canceled your order ${id}.`)
})
}
function TrackOrderCommand(id) {
return new Command(() => {
console.log(`Your order will ${id} will arrive in 20 minutes.`)
})
}
const manager = new OrderManager()
manager.execute(new PlaceOrderCommand('Pad Thai', 1234)) // You have successfully ordered Pad Thai (1234).
manager.execute(new TrackOrderCommand(1234)) // Your order will 1234 will arrive in 20 minutes.
manager.execute(new CancelOrderCommand(1234)) // You have canceled your order 1234.
class Chatroom {
logMessage(user, message) {
const sender = user.getName()
console.log(`${new Date().toLocaleString()} [${sender}]: ${message}`)
}
}
class User {
constructor(name, chatroom) {
this.name = name
this.chatroom = chatroom
}
getName() {
return this.name
}
send(message) {
this.chatroom.logMessage(this, message)
}
}
const chatroom = new Chatroom()
const user1 = new User('Hao', chatroom)
const user2 = new User('John', chatroom)
user1.send('Hello') // 1/17/2022, 6:51:44 PM [Hao]: Hello
user2.send('Hi') // 1/17/2022, 6:52:02 PM [John]: Hi
class Dog {
constructor(name) {
this.name = name
}
}
const dogFunctionality = {
bark: () => console.log('Woof!'),
wagTail: () => console.log('Wagging my tail!'),
play: () => console.log('Playing!'),
}
Object.assign(Dog.prototype, dogFunctionality)
const pet1 = new Dog('Daisy')
pet1.name // Daisy
pet1.bark() // Woof!
pet1.play() // Playing!
class Observable {
observers = new Set()
subscribe(observer) {
this.observers.add(observer)
return () => this.unsubscribe(observer)
}
unsubscribe(observer) {
this.observers.delete(observer)
console.log(`observer unsubscribed.`)
return this
}
publish(data) {
this.observers.forEach((observer) => observer?.(data))
}
}
const observable = new Observable()
observable.subscribe((data) => console.log(`observer1: ${data}`))
const unsubscribeObserver2 = observable.subscribe((data) => {
console.log(`observer2: ${data}`)
})
observable.publish('Holy 💩')
// observer1: Holy 💩
// observer2: Holy 💩
unsubscribeObserver2() // observer unsubscribed.
observable.publish('observer2 is gone.') // observer1: observer2 is gone.
const person = {
name: 'hao',
age: 26,
gender: 'male',
}
// use Reflect instead of obj[prop]
const personProxy = new Proxy(person, {
get(obj, prop) {
console.log(`hao's gender is ${Reflect.get(obj, prop)}.`)
},
set(obj, prop, value) {
if (prop === 'age') {
console.error(`you can't go back in time.`)
return
}
console.log(`changing ${obj.name}'s ${prop} to ${value}.`)
Reflect.set(obj, prop)
},
})
personProxy.gender // hao's gender is male.
personProxy.age = 18 // can't go back in time
personProxy.age // hao's gender is 26.
// use cases: validation, formatting, notifications, or debugging.
// downsides: performance
// singleton: classes can be only instantiated once
let instance = null
class Counter {
constructor() {
if (instance) {
throw new Error('Only one instance of Counter is allowed.')
}
instance = this
this.count = 0
}
getInstance() {
return this
}
getCount() {
return this.count
}
increment() {
return ++this.count
}
decrement() {
return --this.count
}
}
const c1 = new Counter()
// const c2 = new Counter() // error
Object.freeze(c1) // prevent from being modified
export default c1
// downsides
// 1. overkill: Objects are passed through reference in JavaScript
// 2. hard to test: order is important
// 3. dependency hiding: can be easily modified and cause unexpected behaviors
// 4. global behavior: commonly used in state management, has to be done right
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment