js css html

JavaScript--设计模式

2022-08-24  本文已影响0人  蒜泥捣莓

一、概述

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

二、原则

S – Single Responsibility Principle 单一职责原则

O – OpenClosed Principle 开放/封闭原则

L – Liskov Substitution Principle 里氏替换原则

I – Interface Segregation Principle 接口隔离原则

D – Dependency Inversion Principle 依赖倒转原则

三、分类

四、示例

4.1单例模式

概述:

一个类只有一个实例(生成出来对象永远只有一个实例),并提供一个访问它的全局访问点。

实现过程:

应用:登录框

闭包实现

function single(){
    let obj //标识
    return function(){
        if(!obj){ //判断是否为undefined
            obj = new Object()
        }
        return obj
    }
}
let singleObj = single()
let obj1 = singleObj()
let obj2 = singleObj()
console.log(obj1===obj2)//true

原型实现

function singlePrototype(){
    if(!Object.prototype.instance){
        Object.prototype.instance = new Object()
    }
    return Object.prototype.instance
}
let obj1 = singlePrototype()
let obj2 = singlePrototype()
console.log(obj1===obj2) //true

static实现

function singleStatic(){
    if(!Object.instance){
        Object.instance = new Object()
    }
    return Object.instance
}
let obj1 = singleStatic()
let obj2 = singleStatic()
console.log(obj1===obj2)

全局变量实现

function singleWindow(){
    if(!window.instance){
        window.instance = new Object()
    }
    return window.instance
}
let obj1 = singleWindow()
let obj2 = singleWindow()
console.log(obj1===obj2)
4.2工厂模式

概述:

工厂模式生产对象的,以一个工厂方法来生产对应的对象。

实现过程:

function factory(){
    let obj = new Object()
    obj.name = 'jack'
    return obj
}
4.3组合模式

概述:

将对应多个相同名字方法 放在一个地方统一调用。

实现:

class SayHello{
    constructor(){
        
    }
    say(){
        console.log('hello')
    }
}
class SayHi{
    constructor(){
        
    }
    say(){
        console.log('hi')
    }
}
class SayBay{
    constructor(){
        
    }
    say(){
        console.log('baybay')
    }
}

以上的三个类 分别都具备一个名为say的方法 如果需要调用的话 那么是一个个的对象进行调用而不能统一调用,如果我需要他统一调用,这个时候我们就可以使用组合模式。

class Combiner{
    constructor(){
        //容器来保存对应的对象
        this.objs = []
    }
    push(obj){
        //添加对象
        this.objs.push(obj)
    }
    excute(fnName){
        //执行对应的方法
        this.objs.forEach(item=>{
            item[fnName]()
        })
    }
}
//新建组合模式对象
let combiner = new Combiner()
//传入对应统一调用的对象
combiner.push(new SayHello())
combiner.push(new SayHi())
combiner.push(new SayBay())
//执行对应的方法
combiner.excute('say')

组合模式在vue中使用

use和install

vue.use()为注册全局插件所用,接收函数或者一个包含install属性的对象为参数,如果参数带有install就执行install, 如果没有就直接将参数当install执行, 第一个参数始终为vue对象, 注册过的插件不会重新注册

4.4观察者模式

概述

场景:

document.body.addEventListener('click', function() {
    console.log('hello world!');
});
document.body.click()

实现:

class ObServer{
    constructor(){
        //事件和对应的处理函数存储的容器
        this.arg = {} //click:[fn,fn1]
    }
    on(){//发布事件
    
    }
    emit(){//执行处理函数
        
    }
    off(){//取消事件
    
    }
}

on方法实现

class ObServer{
    constructor(){
        this.arg = {} //{click:[fn,fn1]}
    }
    on(eventName, handler) { //发布事件 事件名  处理函数
        if (!this.arg[eventName]) { //没有这个事件
            this.arg[eventName] = [] //初始化里面为空数组
        }
        this.arg[eventName].push(handler) //将对应的函数追加
    }
    emit(){//执行处理函数

    }
    off(){//取消事件

    }
}

emit方法实现

class ObServer{
    constructor(){
        this.arg = {} //{click:[fn,fn1]}
    }
    on(eventName, handler) { //发布事件 事件名  处理函数
        if (!this.arg[eventName]) { //没有这个事件
            this.arg[eventName] = [] //初始化里面为空数组
        }
        this.arg[eventName].push(handler) //将对应的函数追加
    }
    emit(eventName, params) { //执行处理函数
        if (!this.arg[eventName]){
            return
        }
        //会将里面的处理函数都执行
        //遍历对应的处理函数数组
        this.arg[eventName].forEach(fn => {
            //将参数传入执行
            fn.call(this, params)
        })
    }
    off(){//取消事件

    }
}

off方法实现

class ObServer {
    constructor() {
        this.arg = {} //{click:[fn,fn1]}
    }
    on(eventName, handler) { //发布事件 事件名  处理函数
        if (!this.arg[eventName]) { //没有这个事件
            this.arg[eventName] = [] //初始化里面为空数组
        }
        this.arg[eventName].push(handler) //将对应的函数追加
    }
    emit(eventName, params) { //执行处理函数
        if (!this.arg[eventName]){
            return
        }
        //会将里面的处理函数都执行
        //遍历对应的处理函数数组
        this.arg[eventName].forEach(fn => {
            //将参数传入执行
            fn.call(this, params)
        })
    }
    off(eventName, handler) { //取消事件
        if (!this.arg[eventName]) {
            return
        }
        //将这个对应的fn删除
        if (this.arg[eventName].length == 1) {
            delete this.arg[eventName]
        } else {
            let i
            this.arg[eventName].forEach((item, index) => {
                if (Object.is(item, handler)) {
                    i = index
                }
            })
            this.arg[eventName].splice(i, 1)
        }
    }
}

扩展在观察者emit方法传入参数 传到对应的on里面的处理函数 vue里面子传父的实现

4.5代理模式

概述:

代理模式利用一个代理对象来处理当前对象事情

假设当A 在心情好的时候收到花,小明表白成功的几率有60%,而当A 在心情差的时候收到花,小明表白的成功率无限趋近于0。小明跟A 刚刚认识两天,还无法辨别A 什么时候心情好。如果不合时宜地把花送给A,花被直接扔掉的可能性很大,这束花可是小明吃了7 天泡面换来的。但是A 的朋友B 却很了解A,所以小明只管把花交给B,B 会监听A 的心情变化,然后选择A 心情好的时候把花转交给A,

es7新增一个类 Proxy 他就是用于代理的,他是vue3的底层实现

Proxy构造函数

new Proxy(目标对象,handler处理对象)

对应的处理对象有4大方法

//目标对象
let target = {name:'张三',age:18,say(){
    console.log('hello');
}}
//利用proxy产生代理对象
let proxy = new Proxy(target,{
    get(target,property,proxy){ //表示目标对象  表示属性名 表示代理对象
        console.log('get调用了');
        //访问值的时候
        if(property =='name'){
            return '我的名字是'+target[property]
        }
        if(property =='age'){
            return '我的年纪是'+target[property]+'岁'
        }
    },
    set(target,property,value){
        //设置值的时候 进行相关操作
        console.log(property);
        console.log(value);
        target[property] = value
    },
    deleteProperty(target,property,proxy){
        //删除属性的时候
        console.log('delete调用了');
        delete target[property]
    },
    has(target,property){
        //in的时候调用 必须返回boolean 强制转换为boolean类型
        console.log('has调用了');
        console.log(property);
        return property in target
    },
    apply(target,property){ //函数调用触发
        console.log('apply调用了');
    }
})
//读取代理对象的属性的时候 会自动调用get方法 他的值是get方法返回的值
console.log(proxy.age); //调用get
proxy.name = 'jack' //调用set
console.log(proxy); 
delete proxy.name //调用deleteProperty
console.log('name' in proxy); //某个东西是否在某个东西里面返回boolean
console.log(proxy.say); //代理只第一层

apply对应的方法

function sum(a, b) {
    return a + b;
}

const handler = {
    apply: function (target, thisArg, argumentsList) { //目标对象 当前this 参数数组
        console.log('apply调用了');
        // expected output: "Calculate sum: 1,2"

        return target(argumentsList[0], argumentsList[1]) * 10;
    }
};

const proxy1 = new Proxy(sum, handler);

console.log(sum(1, 2));
// expected output: 3
console.log(proxy1(1, 2));
// expected output: 30
4.6装饰者模式

概述:

实现:

//原本类
class Car{
    constructor(){
        
    }
    run(){
        console.log('车在跑')
    }
}
//增强的类
class Decorater{
    constructor(car){
        this.car = car
    }
    run(){
        console.log('我边吃饭边开车')
        this.car.run()
    }
}
new Decorater(new Car()).run()

扩展:es7新增一个装饰器 其实就是装饰器模式的封装

4.7适配器模式

概述

将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。

实现:

let phone = {
    fn(){
        retrun '5v'
    }
}
class Target{
    constructor(){
    }
    fn(){
        let v = phone.fn()
        return '220转换为'+v
    }
}
new Target().fn()

应用:

上一篇 下一篇

猜你喜欢

热点阅读