Home  >  Article  >  Web Front-end  >  JavaScript classic explanation of design patterns (detailed examples)

JavaScript classic explanation of design patterns (detailed examples)

WBOY
WBOYforward
2022-02-08 17:37:281671browse

This article brings you relevant knowledge about design patterns in JavaScript, including singleton pattern, combination pattern, observer pattern, etc. I hope it will be helpful to you.

JavaScript classic explanation of design patterns (detailed examples)

1 Design pattern

Concept

A design pattern is a set of optimal solutions designed to solve a certain problem.
Object-oriented - pay more attention to objects - find the best way to define objects and add properties and methods to each object
The best solution found - is a design pattern

for For different problems, we will have different best solutions - Design patterns

Common design patterns:

  • Single case pattern
  • Combined pattern
  • Observer Mode
  • Command Mode
  • Agent Mode
  • Factory Mode
  • Strategy Mode
  • Adapter Mode
  • . . .

1.1 Singleton mode

Database connection - Multiple functions require database operation - Reconnect the database - 1000 functions, connect to the database 1000 times

Registration function, each registration requires operating the database - 1,000 people are registering at the same time

Mysql database has a connection limit: it can only support a maximum of 200 connections at the same time

We connect once Database, get a connection, operate the database multiple times, use this connection to operate it

How to operate, let the database statement be executed multiple times using the same connection-we can design a design pattern

Design pattern: Define a class. After this class is new, it will get a connection. Every time a database statement is executed in the future, you can get a connection from this class.
Singleton mode: You can only get it from one class. An object - no matter how many times this class is operated, all the connection objects finally obtained are the same object

Let all objects created by a class have exactly the same properties and methods. For example, encapsulate a class and put some commonly used operating functions as methods. In the future, the same object will be used to call these methods every time

Normally, each object created by a class is different .

class Carousel{
    }var a = new Carousel();var b = new Carousel();console.log(a === b); // false

The singleton mode is to make the two objects the same, that is to say, a class will always have only one instance object

var single = (function(){
    class Carousel{
       
    }
    var res = undefined;
    return function(){
        if(!res){
           res = new Carousel();
        }
        return res;
    }})();var s1 = single();var s2 = single();console.log(s1 === s2); // true

The variable P exposed to the global variable will cause global pollution.
Use closures to solve the problem of redefining p every time

The core code of singleton mode:

function Person(){}function fn(Person){
    var p;
    return function(){
        if(!p){
            p = new Person;
        }
        return p;
    }}var f = fn(Person)var p1 = f()var p2 = f()

The application scenario of singleton mode is in the encapsulation tool library.

Example: Encapsulate and encapsulate a tool library
Singleton mode application Encapsulate tool library

     工具库中会有很多的方法 - 方法每次的使用 应该是同一个对象使用的,而不是应该每次都有一个新对象在使用工具
       // var t = new Tool;
        // t.setCookie('username', 'zs', 20);
        const Tool = (function () {
            class Tool {
                constructor() {
                    if (window.getComputedStyle) {
                        this.flag = true;
                    } else {
                        this.flag = false;
                    }
                }
                /获取节点属性                getStyle(ele, attr) {
                    if (this.flag) {
                        return window.getComputedStyle(ele)[attr];
                    } else {
                        return ele.currentStyle[attr];
                    }
                }

                getStyle(ele, attr) {
                     尝试一段代码   不知道会不会报错
                     尝试成功 后面代码没有什么事
                    尝试失败 会报错 被cathch 捕获到  会将错误信息放到err参数里  catch{} 里可以处理这个错误 也可以不处理这个错误对上面的错误代码进行补救  错误不会再浏览器里报错                    try {
                        return window.getComputedStyle(ele)[attr];
                    } catch (err) {
                        return ele.currentStyle[attr];
                    }
                }
                // 设置节点css属性
                setStyle(ele, styleObj) {
                    for (let attr in styleObj) {

                        ele.style[attr] = styleObj[attr];
                    }
                }
                // 设置cookie
                setCookie(key, value, second, path = '/') {
                    let data = new Date();
                    date.setTime(date.getTime() - 8 * 3600 * 1000 + second * 1000);
                    document.cookie = `${key}=${value};expires=${date};path=${path}`;
                }
            }
            var tool;
            return (function () {
                if (!tool) {
                    tool = new Tool();
                }
                return tool;
            })();
        })();

1.3 Combination mode

The combination mode is to make a launcher. After multiple classes are instantiated, they use a method with the same name to start. At this time, you can make a launcher to start multiple classes together.

class Carousel{
    init(){
        console.log("轮播图开始运行");
    }}class Tab{
    init(){
        console.log("选项卡开始运行");
    }}class Enlarge{
    init(){
		console.log("放大镜开始运行");
    }}// 这3个类要运行起来需要各自实例化,并调用每个类中的init方法,此时就可以使用组合模式做一个启动器

Combined mode production starter:

class Starter{
    constructor(){
		this.arr = []; // 定义一个数组
    }
    add(className){
        this.arr.push(className); // 将这个多个类放进数组
    }
    run(){
        for(var i=0;i<this.arr.length><hr>
<h3>1.4 Publish and subscribe mode</h3>
<p>https://blog.csdn.net/weixin_44070254/article/details/117574565 ?spm=1001.2014.3001.5501</p>
<p>Someone subscribes and someone publishes<br> Publish and subscribe mode: an observer is required and an observed is required. If the observer finds that the status of the observed has changed, a task needs to be performed. <br> Define an observer: </p>
<pre class="brush:php;toolbar:false">class Observer{
    // 观察者有名字和任务
    constructor(name,task){
        this.name = name        this.task = task    }}// 定义班主任var bzr = new Observer('班主任',function(state){
    console.log("因为"+state+",所以"+this.name+"罚站");})// 定义了一个年级主任var zr = new Observer('年级主任',function(state){
    console.log("因为"+state+",所以"+this.name+"要找班主任");})// 被观察者class Subject{
    // 有自己的状态
    constructor(state){
        this.state = state        // 观察者们
        this.observer = [];
    }
    // 添加被观察者
    add(...arr){
        this.observer = this.observer.concat(arr)
    }
    // 改变状态
    changeSate(state){
        this.state = state        // 触发观察者的任务
        for(let i=0;i<this.observer.length><p>Observer pattern, also known as publish-subscribe pattern. It means to have a person constantly monitor a certain thing. When the thing is about to perform a certain behavior, the person will notify a function to perform the operation of the behavior. </p>
<p>Example: After the event code is written, this event actually continuously monitors the user's behavior on the page. Once the user triggers this event, a function is called to handle the event. </p>
<pre class="brush:php;toolbar:false">p.addEventListener("click",function(){});
// 这个事件写好以后,就一直在页面中监控用户行为,用户点击这个元素的时候,就调用函数

The observer pattern is a similar operation. The purpose of writing the observer pattern is to bind a custom event to a non-element data.

Example: Bind an abc event to an obj

Analysis:

Bind an event to an element, there are binding methods, trigger conditions, and unbinding Certainly.

Bind a custom event to an object. So how to bind this event, how to trigger it, and how to unbind this event.

So:

  • Need a method to handle event binding.
  • Need a method to handle how to trigger this event.
  • Need a method to handle how to unbind this event.

Events of elements, one event type can be bound to multiple processing functions.

How to bind multiple functions to one event type using custom events of objects.

So:

Need a space to store the processing functions corresponding to the event type.

1.4.1 Prototype:

class watch{
    bind(){
        
    }
    touch(){
        
    }
    unbind(){
        
    }}var w = new watch();

At this time, if you want to bind events and processing functions to this object, you need the event type and processing function as parameters, so you need to pass in the actual value when calling. Parameter

var w = new watch();w.bind("cl",a); // 给w对象绑定cl事件类型,执行a函数w.bind("cl",b); // 给w对象绑定cl事件类型,执行b函数function a(){
    console.log("事件处理函数a");}function b(){
    console.log("事件处理函数b");}

1.4.2 Binding

Receive parameters in the bind method and store the event type and processing function correspondingly:

constructor(){
    this.obj = {} // 存储格式:{事件类型:[函数1,函数2]}}bind(type,handle){
    this.obj[type] = [handle]; // 对象存储方式{"cl":[a]}}

If you bind this event again If you define a function b, the original a will be overwritten. Therefore, you should judge first. If there is no data in the corresponding array, just put it directly. If there is, you should add

bind(type,handle){
    if(!this.obj[type]){
        this.obj[type] = [handle]; // 对象存储方式{"cl":[a]}
    }else{
        this.obj[type].push(handle);
    }  }

to print the w object. result:

绑定后的存储结果
JavaScript classic explanation of design patterns (detailed examples)

1.4.3 触发

触发这个事件需要传入触发哪个事件类型

touch(type){
    // 首先要判断,这个事件类型是否绑定,没有绑定不能触发
    if(!this.obj[type]){
        return false;
    }else{
        // 将这个事件的所有绑定的处理函数一起调用
        for(var i=0;i<this.obj><p>测试:</p>
<table>
<thead><tr class="firstRow"><th>触发测试</th></tr></thead>
<tbody>
<tr><td><img src="https://img.php.cn/upload/article/000/000/067/723219bbf42dba49705fd0fe49beab7d-1.png" alt="JavaScript classic explanation of design patterns (detailed examples)"></td></tr>
<tr><td><br></td></tr>
</tbody>
</table>
<p>这两个处理函数都没有参数,如果要传入参数的时候该怎么处理?</p>
<p>触发事件的时候就要传入实参</p>
<pre class="brush:php;toolbar:false">w.touch("cl","张三",20);

触发事件的方法就应该处理这些参数

touch(type,...arr){ // 因为参数不定长,所以使用合并运算符
    // 首先要判断,这个事件类型是否绑定,没有绑定不能触发
    if(!this.obj[type]){
        return false;
    }else{
        // 处理参数:模拟系统事件的参数事件对象,将所有参数都集中在一个对象中
        var e = {
            type:type,
            args:arr        }
        // 将这个事件的所有绑定的处理函数一起调用
        for(var i=0;i<this.obj><p>添加一个带参数的处理函数,并触发事件执行:</p>
<pre class="brush:php;toolbar:false">w.bind("cl",c); // 给w对象绑定cl事件类型,执行c函数w.touch("cl","张三",20);function c(e){
    console.log("我是处理函数c,打印:姓名"+e.name+",年龄"+e.age);}

结果:

带参数的处理函数处理结果
JavaScript classic explanation of design patterns (detailed examples)

1.4.5 解绑

解绑也需要知道解绑的事件类型和处理函数

unbind(type,handle){
    // 先判断是否绑定了这个事件
    if(!this.obj[type]){
        return false;
    }else{
        // 从数组中将这个处理函数删除
        for(var i=0;i<this.obj><p>解绑测试:</p>
<table>
<thead><tr class="firstRow"><th>解绑测试结果</th></tr></thead>
<tbody>
<tr><td><img src="https://img.php.cn/upload/article/000/000/067/723219bbf42dba49705fd0fe49beab7d-3.png" alt="JavaScript classic explanation of design patterns (detailed examples)"></td></tr>
<tr><td><br></td></tr>
</tbody>
</table>
<p>如果绑定事件的时候使用的匿名函数,就无法进行解绑了,所以再添加一个解绑事件所有处理函数的方法:</p>
<pre class="brush:php;toolbar:false">clear(type){
    if(!this.obj[type]){
        return false;
    }else{
        // 直接从对象中将这个属性删除
        delete this.obj[type];
    } }

1.5 观察者模式

观察者模式跟发布订阅模式不一样的地方在于,要有观察者和被观察者。

创建观察者:

// 创建观察者class Observer{
    // 观察者有姓名和技能 - 技能是一个函数
    constructor(name,skill){
        this.name = name;
        this.skill = skill    }}// 创建观察者var bzr = new Observer('班主任',function(state){
    console.log('因为'+state+'叫家长')})var xz = new Observer('校长',function(state){
    console.log('因为'+state+'叫班主任')})console.log(bzr,xz)

JavaScript classic explanation of design patterns (detailed examples)

创建被观察者:

// 创建被观察者
    class Subject{
        // 被观察者有状态 和 观察者列表
        constructor(state){
            this.state = state            this.observers = []
        }
        // 添加观察者
        addObserver(observer){
            var index = this.observers.findIndex(v=>v === observer)
            if(index{
                    v.skill(this.state)
                })
            }
        }
        // 删除观察者
        delObserver(observer){
            var index = this.observers.findIndex(v=>v === observer)
            if(index>=0){
                this.observers.splice(index,1)
            }
        }
    }
    // 创建被观察者
    var xm = new Subject('学习')
    // 添加观察者
    xm.addObserver(bzr)
    xm.addObserver(xz)
    xm.addObserver(bzr)
    console.log(xm)
    // 改变状态
    xm.setState('玩游戏')

JavaScript classic explanation of design patterns (detailed examples)


1.6 策略模式

一个问题有多种解决方案,且随时还可以有更多的解决方案,就是策略模式。例如:一个商品在售卖的时候,会有多种折扣方式,慢100减10元,满200减30元等…

商品活动:
满100减10
满200减30
满300打8折

策略模式:将折扣放在闭包中保存起来 - 通过闭包对折扣进行增删改查操作

正常的函数表达方式:

function fn(type,price){
    if(type === '100_10'){
       return price -= 10
    }else if(type === '200_30'){
       return price -= 0
    }else{
        return '没有这种折扣'
    }}fn('100_10',160)

这种方式,在添加折扣或删除折扣的时候总是需要修改原函数。

策略模式代码:

var calcPrice = (function(){
    // 以闭包的形式存储折扣数据
    var sale = {
        '100_10':function(price){
            return price -= 10
        },
        '200_20':function(price){
            return price -= 20
        }
    }
    function calcPrice(type,price){
        // 闭包中使用折扣
        if(type in sale){
            return sale[type](price)
        }else{
            return '没有这个折扣'
        }
    }
    // 折扣函数添加属性 - 添加折扣
    calcPrice.add = function(type,fn){
        if(type in sale){
            console.log('折扣存在')
        }else{
            sale[type] = fn        }
    }
    // 删除折扣
    calcPrice.del = function(type){
        if(type in sale){
            delete sale[type]
        }else{
            console.log('折扣不存在')
        }
    }
    return calcPrice})()var p = calcPrice('100_10',200)calcPrice.add('200_320',function(price){
    return price -= 50})calcPrice.del('200_330')var p = calcPrice('200_320',200)console.log(p)

相关推荐:javascript学习教程

The above is the detailed content of JavaScript classic explanation of design patterns (detailed examples). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete