Skip to content

Instantly share code, notes, and snippets.

@toan2406
Last active February 10, 2017 07:00
Show Gist options
  • Save toan2406/dd65a3dbb0b0e3887c87ab9988d9985e to your computer and use it in GitHub Desktop.
Save toan2406/dd65a3dbb0b0e3887c87ab9988d9985e to your computer and use it in GitHub Desktop.
/**
* This pattern has 4 main parts: command object, client, invoker, receiver.
* It's an abstraction layer between the object that implements a method and the
* object that wishes to invoke that method. It exists because some languages
* don't have first-class functions/lambdas.
*/
// Receiver
const Post = function (title) {
this.title = title
}
Post.prototype.save = function () {
console.log(`Created post: ${JSON.stringify(this)}`)
}
Post.prototype.set = function (key, value) {
this[key] = value
}
// Command
const SavePost = function (post) {
this.post = post
}
SavePost.prototype.execute = function () {
this.post.save()
}
const UpdatePost = function (post) {
this.post = post
}
UpdatePost.prototype.execute = function (obj) {
for (let key in obj) {
this.post.set(key, obj[key])
}
}
// Client
const post = new Post('Hello, world!')
const savePost = new SavePost(post)
const updatePost = new UpdatePost(post)
// ...and bind it to the button click event
// Invoker
// ...when user clicks on the buttons
updatePost.execute({ author: 'Toan' })
savePost.execute()
function Action (type, payload) {
this.type = type
this.payload = payload
}
Action.prototype.toString = function () {
return this.type
}
const getUsers = new Action('GET_USERS', [{ name: 'Toan' }])
console.log(getUsers)
console.log(getUsers + '')
const fs = require('fs')
// Hide underlying complexity
function logError (message) {
fs.appendFile('log.txt', `ERROR: ${message}\n`)
}
logError('Can not connect to MongoDB')
/*
* The ground rules for a mediator pattern is as follows:
* - A mediator works with objects that have indirect relationships. The set the rules for interaction between these objects.
* - Mediator knows all components and its methods.
* - Mediator decides what to do - that is the business logic embedded in the mediator dictates what the co-ordination between objects.
* - Mediator is best used to abstract the workflow logic at a higher level.
* - A wizard dialog maybe a good example of a mediator pattern.
*/
const Mediator = (function () {
const obj = function () {
let subscribers = {}
const publish = function (message, from, to) {
if (to) {
if (!subscribers[to.name]) {
console.error(`ERROR: message NOT sent from: ${from.name} to: ${to.name}`)
} else {
to.receive(message, from)
}
} else {
for (let key in subscribers) {
if (subscribers[key] !== from) {
subscribers[key].receive(message, from)
}
}
}
}
const subscribe = function (subscriber) {
subscribers[subscriber.name] = subscriber
subscriber.mediator = this
}
const unsubscribe = function (subscriber) {
delete subscribers[subscriber.name]
}
return {
publish,
subscribe,
unsubscribe
}
}
return obj
})()
const Subscriber = function (name) {
this.name = name
this.mediator = null
}
Subscriber.prototype.send = function (message, to) {
if (this.mediator) {
this.mediator.publish(message, this, to)
}
}
Subscriber.prototype.receive = function (message, from) {
console.log(`message: ${message} from: ${from.name} to: ${this.name}`)
}
Subscriber.prototype.close = function () {
if (this.mediator) {
this.mediator.unsubscribe(this)
}
}
const chatroom = new Mediator()
const user1 = new Subscriber('Toan')
const user2 = new Subscriber('Khanh')
const user3 = new Subscriber('Bao')
const user4 = new Subscriber('Nga')
chatroom.subscribe(user1)
chatroom.subscribe(user2)
chatroom.subscribe(user3)
chatroom.subscribe(user4)
user1.send('User1 broadcasts to all')
user1.send('User1 broadcasts to 2', user2)
user1.send('User1 broadcasts to 3', user3)
user1.send('User1 broadcasts to 4', user4)
user2.close()
user1.send('User1 broadcasts to all')
user1.send('User1 broadcasts to 2', user2)
// Revealing Module Pattern
const logger = (function () {
let logs = []
// all methods are private
const addLog = (log) => {
logs.push(log)
}
const printLogs = () => {
console.log(logs.join('\n'))
}
// reveal methods
return {
add: addLog,
print: printLogs
}
})()
logger.add('Server listen on 3000')
logger.add('GET /users/ 200')
logger.print()
logger.add('POST /users/ 404')
logger.print()
function ObserverList () {
this.observerList = []
}
ObserverList.prototype.add = function (obj) {
return this.observerList.push(obj)
}
ObserverList.prototype.count = function () {
return this.observerList.length
}
ObserverList.prototype.get = function (index) {
if (index > -1 && index < this.observerList.length) {
return this.observerList[index]
}
}
ObserverList.prototype.indexOf = function (obj, startIndex) {
let i = startIndex
while (i < this.observerList.length) {
if (this.observerList[i] === obj) {
return i
}
i++
}
return -1
}
ObserverList.prototype.removeAt = function (index) {
this.observerList.splice(index, 1)
}
// Subject
function Subject () {
this.observers = new ObserverList()
}
Subject.prototype.addObserver = function (observer) {
this.observers.add(observer)
}
Subject.prototype.removeObserver = function (observer) {
this.observers.removeAt(this.observers.indexOf(observer, 0))
}
Subject.prototype.notify = function (context) {
const observerCount = this.observers.count()
for (var i = 0; i < observerCount; i++) {
this.observers.get(i).update(context)
}
}
// Observer
function Observer (name) {
this.name = name
}
// Example (can be used for lazy loading also)
const checkAllCheckbox = new Subject()
const checkbox1 = new Observer('Checkbox 1')
const checkbox2 = new Observer('Checkbox 2')
checkbox1.update = function (isChecked) {
console.log(`${this.name} is ${isChecked ? 'checked' : 'unchecked'}`)
}
checkbox2.update = function (isChecked) {
console.log(`${this.name} is ${isChecked ? 'checked' : 'unchecked'}`)
}
checkAllCheckbox.addObserver(checkbox1)
checkAllCheckbox.addObserver(checkbox2)
checkAllCheckbox.notify(true)
checkAllCheckbox.notify(false)
const actionPrototype = {
init: function (type, payload) {
this.type = type
this.payload = payload
return this
},
toString: function () {
return this.type
}
}
const getUsers = Object.create(actionPrototype).init('GET_USERS', [{ name: 'Toan' }])
console.log(getUsers.__proto__)
console.log(getUsers)
console.log(getUsers.toString())
/*
* The ground rules for a PubSub pattern is as follows:
* - PubSub works best when the objects are either totally unrelated or there are too many of them to deal with.
* - The publisher does not know the methods the subscribers have. That is, subscribers send the dispatch/callback methods to the publisher.
* - Pubsub is a messaging pattern. It is the sibling of the message queue paradigm
*/
const Publisher = (function () {
const obj = function () {
let topics = {}
const publish = function (topic, args) {
if (!topics[topic]) {
return false
}
const subscribers = topics[topic]
let len = subscribers.length
while (len--) {
subscribers[len](topic, args)
}
return this
}
const subscribe = function (topic, func) {
if (!topics[topic]) {
topics[topic] = []
}
topics[topic].push(func)
}
const unsubscribe = function (subscriber) {
for (let m in topics) {
if (topics[m]) {
for (let i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i] === subscriber) {
topics[m].splice(i, 1)
}
}
}
}
}
return {
publish: publish,
subscribe: subscribe,
unsubscribe: unsubscribe,
trigger: publish,
on: subscribe,
off: unsubscribe
}
}
return obj
})()
const button = new Publisher()
button.toString = () => JSON.stringify({element: 'button', class: 'my-button'})
const subscriber1 = (topic, message) => console.log(`Subscriber 1: ${topic}: ${message}`)
const subscriber2 = (topic, message) => console.log(`Subscriber 2: ${topic}: ${message}`)
const subscriber3 = (topic, message) => console.log(`Subscriber 3: ${topic}: ${message}`)
button.on('click', subscriber1)
button.on('click', subscriber2)
button.on('hover', subscriber3)
button.trigger('click', button)
button.off(subscriber1)
button
.trigger('click', button)
.trigger('hover', button)
button.off(subscriber2)
button.off(subscriber3)
const GeneratedUser = (function () {
let instance
function User () {
this.id = (Math.random() * 1000).toFixed(0)
}
User.prototype.setName = function (name) {
this.name = name
}
return {
getInstance: function () {
if (!instance) {
instance = new User()
}
return instance
}
}
})()
const currentUser = GeneratedUser.getInstance()
currentUser.setName('Khanh')
const localUser = GeneratedUser.getInstance()
console.log(localUser)
console.log(currentUser === localUser)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment