What are design patterns

In software design, an introduction to elegant solutions to specific problems

In the actual development process, we will have a variety of different needs, and there are many solutions to the needs. We need the solutions to be sustainable, so that we can use them when we meet similar needs next time, and avoid repeating the wheel.

SOLID five design principles

Principle of single responsibility

Is a program only focus on the execution of one thing, in this event will not complete the function of other events, the logic is relatively simple, not very complex

O Open and closed principle

Open to extension, closed to modification. Our code needs to be extensible, because requirements will be updated, but we cannot change the code of other original requirements because of new requirements, so we need to be closed to modification.

L Richter’s substitution principle

First, there is a parent class, according to the parent class to inherit the subclass, the subclass can cover the functions of the parent class, based on the parent class to expand more functions, and can appear in the place where the parent class appears. Extensible and functional.

I Interface independence principle

Keep the interfaces single and independent and do not affect each other.

D) dependence leads to the principle

Usage methods focus only on the interface and not on the implementation of concrete classes

Why are design patterns needed

legibility

Using design patterns can improve the readability of code and the efficiency of subsequent development

Can expand sex

Using design patterns to decouple code is a great way to enhance code’s modifiability and extensibility

reusability

Design patterns allow you to reuse existing solutions without redoing the same work

reliability

Using design patterns increases the robustness of the system and makes code authoring truly engineering

Common Design Patterns

The singleton pattern

Definition: unique & global access. Ensure that a class has only one instance and provide a global access point to access it

Application scenario: Contents that can be cached can be reused, for example, login pop-ups

// Business logic
const createLoginLayer = () = >{
    const div = document.createElement("div")
    div.innerHTML = "Login to floating window"
    div.style.display = "none"
    document.body.appendChild(div)
    return div
}
​
document.getElementById("loginBtn").onclick = () = >{
    const loginLayer = createLoginLayer()
    loginLayer.style.display = "block"
}
Copy the code

Use the singleton pattern

/ / the singleton
const getSingle = (fn) = >{
    let result;
    return(. rest) = >{
        return result || (result = fn.apply(this,rest))
    }
}
​
// Business logic
const createLoginLayer = () = >{
    const div = document.createElement("div")
    div.innerHTML = "Login to floating window"
    div.style.display = "none"
    document.body.appendChild(div)
    return div
}
​
const createSingleLohinLayer = getSingle(createLoginLayer)
​
document.getElementById("loginBtn").onclick = () = >{
    const loginLayer = createSingleLohinLayer()
    loginLayer.style.display = "block"
}
Copy the code

The strategy pattern

Definition: a series of algorithms that encapsulate and interchangeable seemingly unrelated code, encapsulate, reuse, and make it easier to understand and extend

Application scenario: There are different strategies to accomplish one thing, such as performance calculation, form validation rules

/ / strategy
const calculateBonus = (level,salary) = >{
    switch (level){
        case 's': {return salary * 4
        }
        case 'a': {return salary * 3
        }
        case 'b': {return salary * 2
        }
        default: {return 0
        }
    }
}
​
calculateBonus("s".20000) / / 80000
calculateBonus("a".10000) / / 30000
Copy the code

Using the Policy Pattern

/ / strategy
const strategies = {
    s:(salary) = >{
        return salary * 4
    },
    a:(salary) = >{
        return salary * 3
    },
    b:(salary) = >{
        return salary * 2}},const calculateBonus = (level,salary) = >{
    return strategies[level](salary)
}
​
calculateBonus("s".20000) / / 80000
calculateBonus("a".10000) / / 30000
Copy the code

The proxy pattern

Definition: Provides a proxy or placeholder for an object that controls access to it once. A surrogate object can preprocess the request before deciding whether to hand it to the ontology object

Application scenario: When direct access to an object is not convenient, or the requirements are not met, we can consider using a surrogate object to control access to the object

// Native functions
const rawImage = (() = >{
    const imgNode = document.createElement('img')
    document.body.appendChild(imgNode)
    return {
        setSrc:(src) = >{
            imgNode.src = "./loading.gif"
            const img = new Image()
            img.src = src
            img.onload = () = >{
                imgNode.src = this.src
            }
        }
    }
})()
​
rawImage.setSrc("http://xxx.gif")
Copy the code
// Native functions
const rawImage = (() = >{
    const imgNode = document.createElement('img')
    document.body.appendChild(imgNode)
    return {
        setSrc:(src) = >{
            imgNode.src = src
        }
    }
})()
​
​
// proxy function
const proxyImage = (() = >{
    const img = new Image()
    img.onload = () = >{
        rawImage.setSrc(this.src)
    }
    return {
        setSrc:(src) = >{
            rawImage.setSrc('./loading.gif')
            img.src = src
        }
    }
})()
​
proxyImage.setSrc("http://xxx.gif")
Copy the code

Publish and subscribe model

Definition: A one-to-many dependency between objects when an object’s state changes. All objects that depend on it will be notified

Application scenario: DOM events, message notification

class PubSub {
    constructor(){
        this.subscriber = {}
    }
    / / subscribe
    subscribe(type,fn){
        let listeners = this.subscribers[type] || []
        listeners.push(fn)
    }
    // Unsubscribe
    unsubcribe(type,fn){
        let listeners = this.subscribers[type]
        if(! listeners || ! listeners.length)return
        this.subscribers[type] = listeners.filter((v) = >v ! == fn) }// Triggers the subscription event
    public(type,... args){
        let listeners = this.subscribers[type]
        if(! listeners || ! listeners.length)return
        listeners.forEach((fn) = >fn(... args)) } }let ob = new PubSub()
ob.subscribe("add".(val) = >console.log(val))
ob.publish("add".1)
Copy the code

Command mode

Definition: an instruction to do something specific

Application scenario: Rich text editor toolbar

// Set the command
const setCommand = (button,command) = >{
    button.onclick = () = >{
        command.execute()
    }
}
​
// Business logic
const MenuBar = {
    refresh:() = >{
        console.log("refresh")}}const RefreshMenuBarCommand = (receiver) = >{
    return {
        execute:() = >{
            receiver.refresh()
        }
    }
}
​
const refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar)
​
// Bind buttons and commands
setCommand(refreshButton,refreshMenuBarCommand)
Copy the code

Portfolio model

Definition: Use small child objects to build larger objects, and combine objects into a tree structure to represent a partial-whole hierarchy

Application scenario: Is-is to HAS-A

class MacroCommand{
    constructor(){
        this.commands = []
    }
    // Add child object logic
    add(command){
        console.log(this)
        this.commands.push(command)
    }
    // Execute the parent object logic
    execute(){
        for(let i = 0; i <this.commands.length; i++){
            this.commands[i].execute()
        }
    }
}
​
const macroCommand = MacroCommand()
const openCommand = {
    execute:() = >{
        console.log('open')}}const closeCommand = {
    execute:() = >{
        console.log('close')
    }
}
​
marcoCommand.add(openCommand)
marcoCommand.add(closeCommand)
marcoCommand.execute()
Copy the code

Decorator mode

Definition: The ability to dynamically add responsibilities to an object while the program is running without changing the object itself

Application scenario: Data reporting and statistics function execution time

const ajax = (type,url,param) = >{
    console.log(param)
}
​
const getToken = () = >{
    return 'Token'
}
​
ajax()
getToken()
Copy the code
// Add blame
Function.prototype.before = function (beforeFn){
    return (. rest) = >{
        beforeFn.apply(this,rest)
        return this(... rest) } }let ajax = (type,url,param) = >{
    console.log(param)
}
​
const getToken = () = >{
    return 'Token'
}
​
ajax = ajax.before((type,url,param) = >{
    param.token = getToken()
})
Copy the code

Adapter mode

Definition: Resolves interface incompatibilities between two software entities by enabling them to work together without changing existing interfaces

Application scenario: Incompatible interfaces

const aMap = {
    show:() = >{
        console.log('Start rendering map A')}}const bMap = {
    display:() = >{
        console.log('Start rendering map B')}}const renderMap = (type) = >{
    if(type == 'a'){
        aMap.show()
    }else if(type == 'b'){
        bMap.display()
    }
}
Copy the code
const aMap = {
    show:() = >{
        console.log('Start rendering map A')}}const bMap = {
    display:() = >{
        console.log('Start rendering map B')}}/ / adaptation layer
const bMapAdapter = {
    show:() = >{
        return bMap.display()
    }
}
​
const renderMap = (map) = >{
    if(map.show instanceof Function){
        map.show()
    }
}
​
renderMap(aMap)
renderMap(bAdapter)
Copy the code

conclusion

  • Understand the idea of using design patterns and consider the implications and techniques of each design pattern
  • Use design patterns wisely and flexibly in different scenarios. Prioritize. If the project needs to go live, the first goal should be to implement features, not blindly use them
  • Summarizing the experience of using design patterns can help us save a lot of thinking time, select the optimal design pattern for a scene and improve work efficiency because the actual requirements are very complicated
  • The same requirement may apply to different design patterns in different scenarios, so the use of design patterns needs to be integrated, not rigid use