JS设计模式(3)--- 复习

31 阅读2分钟

JS设计模式(3)--- 复习

目录

[TOC]

桥接模式

侨接模式:将抽象部分与他的实现部分分离,使他们都可以独立的变化

使用场景,一个类存在两个或多个独立变化的维度,且这两个维度都需要扩展

优点 把抽象与实现隔离开,有助于独立管理各组成部分

缺点 每使用一个桥接元素都要增加一次函数调用,这样对应用程序的性能有一些负面的话影响提高了系统的复杂程度

    function Aodi1(engine) {
        this.engine = engine
    }
    Aodi1.prototype.platform = function () {
        console.log('Aodi1 平台');
    }
    Aodi1.prototype.loadEngine = function () {
        this.engine.run()
    }
    function v6(params) {
        this.run = function () {
            console.log('v6发动机');
        }
    }
    function v8(params) {
        this.run = function () {
            console.log('v8发动机');
        }
    }
    let car1 = new Aodi1(new v6())
    let car2 = new Aodi1(new v8())
    car1.loadEngine()
    car2.loadEngine()

组合模式

组合模式在对象间形成树行结构

组合模式中基本对象和组合对象一致对待

无需关心对象多少层,调用时只需要在根部进行调用

他在我们树形结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部解耦

 const Folder = function (falder) {
        this.falder = falder
        this.list = []//保存子文件夹或者文件
    }
    Folder.prototype.add = function (res) {
        this.list.push(res)
    }
    Folder.prototype.scan = function () {
        console.log('扫描文件夹', this.falder);
        for (let i = 0; i < this.list.length; i++) {
            this.list[i].scan()
        }
    }
    const File = function (file) {
        this.file = file
    }
    File.prototype.scan = function () {
        console.log('开始扫描文件', this.file);
    }
    //根
    let rootFolder = new Folder('root')
    //子文件件
    let htmlFolder = new Folder('html')
    let cssFolder = new Folder('css')
    let jsFolder = new Folder('js')
    rootFolder.add(htmlFolder)
    rootFolder.add(cssFolder)
    rootFolder.add(jsFolder)
 
    //文件
    let html4 = new File('html4')
    let html5 = new File('html5')
    let css2 = new File('css2')
    let css3 = new File('css3')
    let es5 = new File('es5')
    let es6 = new File('es6')
    htmlFolder.add(html4)
    htmlFolder.add(html5)
    cssFolder.add(css2)
    cssFolder.add(css3)
    jsFolder.add(es5)
    jsFolder.add(es6)
    console.log(rootFolder);
    rootFolder.scan()

命令模式

有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,需要一种松耦合的方式来设计程序,使得发送者和接收者能够消除彼此之间的耦合关系 ·

命令模式由三种角色构成

  • 发布者:发出命令,调用命令对象,不知道如何执行与谁执行
  • 接收者:提供对应接口请求处理,不知道谁发起请求
  • 命令对象:接收命令,调用接收者对应借口处理发布者的请求
 class MacroCommand {
        constructor() {
            this.list = []//子命令对象
        }
        add(command) {
            this.list.push(command)
        }
        execute() {
            for (const item of this.list) {
                item.execute()
            }
        }
    }
    const Tabs = {
        execute() {
            console.log("选项卡执行");
        }
    }
    const Swiper = {
        execute() {
            console.log("轮播执行");
        }
    }
    let macroCommand = new MacroCommand
    macroCommand.add(Swiper)
    macroCommand.add(Tabs)
    macroCommand.execute()

迭代器模式

迭代器模式是提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示,迭代器模式可以把迭代的过程从业务逻辑中分析出来,在使用迭代器模式后,即使不关心对象的内部构造,也可以顺序访问其中的每个元素

  • 为遍历不同的数据结构的集合提供统一接口
  • 能遍历访问集合中的项,不关心项的数据结构
 let kerwinEach = function (arr, callback) {
        for (let i = 0; i < arr.length; i++) {
            callback(i, arr[i])
        }
    }
    kerwinEach([1, 2, 3], function (index, item) {
        console.log(index, item);
    })

es6 iterator

Array map set string arguments nodelist

for of 会调用 [Symbol.iterator]

    let kerwinEach = function (arr, callback) {
        for (let i = 0; i < arr.length; i++) {
            callback(i, arr[i])
        }
    }
    kerwinEach([1, 2, 3], function (index, item) {
        console.log(index, item);
    })
    let list = [4, 5, 6]
    let it = list[Symbol.iterator]()
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    let obj = {
        0: 'zs',
        1: 'ls',
        2: 'ww',
        length: 3,
        [Symbol.iterator]: Array.prototype[Symbol.iterator]
    }
    for (const iterator of obj) {
        console.log(iterator);
 
    }

职责链模式

使多个对象可以处理请求,从而避免了请求的发送者,与多个接收者直接的耦合关系,将这些接收者链接成一条链,顺着这条链传递该请求,直到找到能处理该请求的对象

  btn.onclick = function () {
        checks.check()
        // if (input.value.length == 0) {
        //     console.log('这里不能为空');
        // } else {
        //     if (Number.isNaN(+input.value)) {
        //         console.log('必须是数字');
        //     } else {
        //         if (input.value.length < 6) {
        //             console.log('必须要大于6个数字');
        //         }
        //     }
        // }
    }
    function checkEmty(params) {
        if (input.value.length == 0) {
            console.log('这里不能为空');
            return
        }
        return 'next'
    }
    function checkNumber(params) {
        if (Number.isNaN(+input.value)) {
            console.log('必须是数字');
            return
 
        }
        return 'next'
    }
    function checkLength(params) {
        if (input.value.length < 6) {
            console.log('必须要大于6个数字');
            return
 
        }
        return 'next'
    }
    class Chain {
        constructor(fn) {
            this.checkRule = fn
            this.nexRule = null
        }
        addRule(nexRule) {
            this.nexRule = nexRule
        }
        check() {
            this.checkRule() === 'next' ? this.nexRule.check() : null
        }
    }
    let checks = new Chain(checkEmty)
    const checkNumberChain = new Chain(checkNumber)
    const checkLengthChain = new Chain(checkLength)
    checks.addRule(checkNumberChain)
    checks.addRule(checkLengthChain)
    checkLengthChain.addRule({
        check: () => {
            console.log('ok');
            return 'end'
        }
    })

优点

  • 符合单一单职责,使每个方法中只有一个职责
  • 符合开放封闭原则,在需求增加时,可以很方便的扩冲新的职责
  • 使用时不需要知道谁才是真正的处理方法,减少大量的if else语法

缺点

  • 团队成员需要对职责链存在共识,否则当看到一个方法莫名其妙的返回一个next时一定会奇怪
  • 出现错误时不好排查,因为不知道在那个责任中出的错,需要从链头开始往后找