Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

设计模式初探 (2021-12-22) #28

Open
yaogengzhu opened this issue Dec 22, 2021 · 9 comments
Open

设计模式初探 (2021-12-22) #28

yaogengzhu opened this issue Dec 22, 2021 · 9 comments
Labels
设计模式 Pull requests that update a dependency file

Comments

@yaogengzhu
Copy link
Owner

yaogengzhu commented Dec 22, 2021

策略模式

策略模式:定义一系列的算法,把她们一个个封装起来
模式目的:就是将算法的使用 和 算法的实现分离开来

/**
 *  策略类 + 环境类  (两个部分组成)
 *
 *  策略类: 封装了具体的算法,并负责具体的计算过程
 *  环境类: 接收客户的请求,随后把请求委托给某一个策略类
 *
 *  环境类中--- 维持着某个策略对象的引用
 */

// 策略类
var performaceS = function () {}
performaceS.prototype.calculate = function (salary) {
    return salary * 4
}

// 定义奖金类   ---环境类
var Bonus = function () {
    this.salary = null // 原始工资
    this.strategy = null // 绩效等级对应的策略对象
}

Bonus.prototype.setSalary = function (salary) {
    this.salary = salary // 设置员工的原始工资
}

Bonus.prototype.setStrategy = function (strategy) {
    this.strategy = strategy // 设置员工绩效等级对应的策略对象
}

Bonus.prototype.getBonus = function () {
    // 取得奖金数额
    if (!this.strategy) {
        throw Error('未设置strateg 属性')
    }

    return this.strategy.calculate(this.salary) // 把计算的奖金委托给对应的策略对象
}

var bonus = new Bonus()
bonus.setSalary(1000)
bonus.setStrategy(new performaceS())
console.log(bonus.getBonus())
@yaogengzhu yaogengzhu added the 设计模式 Pull requests that update a dependency file label Dec 22, 2021
@yaogengzhu
Copy link
Owner Author

yaogengzhu commented Dec 30, 2021

单例模式

定义:保证一个类只有一个实例,并提供一个访问它的全局访问点
原理: 用一个变量那个来标志当前是否为莫个类创建过对象。

/**
 * 对现有的类,实现单例模式
 * 代理类实现单例模式
 */

class SingleMode {
    constructor(name) {
        this.name = name
    }

    getName() {
        return this.name
    }
}

const ProxySingleMode = (function(){
    let instance
    return function () {
        if (!instance) {
            instance = new SingleMode()
        }
        return instance
    }
})()

// 类的实现
// class ProxySingleMode {
//     static instance
//     constructor() {
//         if (!ProxySingleMode.instance) {
//             ProxySingleMode.instance = new SingleMode()
//         }
//         return ProxySingleMode.instance;
//     }
// }
const single = new ProxySingleMode()
const single1 = new ProxySingleMode()
console.log(single === single1) // true

惰性单列
定义: 指的是在需要的时候才创建的对象实例子

const getSingle = function (fn) {
    let instance
    return function () {
        return instance || instance === fn.apply(this, arguments)
    }
}

@yaogengzhu
Copy link
Owner Author

yaogengzhu commented Dec 31, 2021

代理模式

定义:代理是为一个对象提供一个替代品或者占位符,以便控制对它的访问

优点:对象本身不好处理的事情,交给代理处理

const Flower = function () {}

const xiaoming = {
    sendFlower: function (target) {
        const flower = new Flower()
        target.receiveFlower(flower)
    },
}

const A = {
    receiveFlower: function (flower) {
        console.log('收到花了')
    },
}

const B = {
    receiveFlower: function (flower) {
        A.receiveFlower(flower)
    },
}

xiaoming.sendFlower(B)

衍生 保护代理虚拟代理

@yaogengzhu
Copy link
Owner Author

yaogengzhu commented Jan 4, 2022

迭代器模式

定义: 是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部状态

迭代器分为两种: 内部迭代外部迭代

内部迭代

const each = function (arr, callback) {
    for (let i = 0; i < arr.length; i++) {
        callback.call(arr[i], i, arr[i])
    }
}

each([1, 2, 4], function (i, v) {
    console.log(i, v)
})

外部迭代

外部迭代虽然调用方式相对复杂,但适用面更广,也能满足更多的需求。
内外迭代模式在生产中,没有优劣之分

const Iterator = function (obj) {
    var current = 0

    var next = function () {
        current += 1
    }

    var isDone = function () {
        return current >= obj.length
    }

    var getCurrentItem = function () {
        return obj[current]
    }

    return {
        next,
        isDone,
        getCurrentItem,
        length: obj.length,
    }
}

// 改写外部迭代模式
const compareOutter = function (iterator1, iterator2) {
    if (iterator1.length !== iterator2.length) {
        return console.log('iterator1 和 iterator2 不相等')
    }

    while (!iterator1.isDone() && !iterator2.isDone()) {
        if (iterator1.getCurrentItem() !== iterator2.getCurrentItem()) {
            return console.log('iterator1 和 iterator2 不相等')
        }

        iterator1.next()
        iterator2.next()
    }

    console.log('相等')
}
let iterator1 = Iterator([1, 2, 3])
let iterator2 = Iterator([1, 2, 3, 4])

compareOutter(iterator1, iterator2)

倒叙迭代

const fallEach = function (arr, callback) {
  for (let i = arr.length - 1; i >= 0; i--) {
      callback(i, arr[i])
  }
}

fallEach([1, 2, 3], function (i, k) {
  console.log(i, k)
})

中止迭代

const breakEach = function (arr, callback) {
    for (let i = 0; i < arr.length; i++) {
        if (callback(i, arr[i]) === false) {
            break
        }
    }
}

breakEach([1, 2, 3, 4], function (i, n) {
    if (n > 3) return false
    console.log(n)
})

迭代器的应用举例

根据浏览器环境获取不同的上传方式

  • 提供一个可被迭代的方法,使getActiveUploadObj, getFlashUploadObj,getFormUploadObj 可以按照优先级被循环迭代
  • 如果正在被迭代的函数返回一个对象,则表示找到了正确的upload对象,反之如果该函数返回false,则迭代器继续工作
const getActiveUploadObj = function() {
    try {
        retrun new ActiveXObject('IE上传')
    } catch(e) {
        return false
    }
}

const getFlashUploadObj = function() {
    if (supportFlash()) { // 省略该方法
        var str  = `<object type='xx'></object>` // 省写
        return $(str).appendTo($('body'))
    }
    return false
}

const getFormUploadObj = function() {
    var str = `<input type='file' />`
    return $(str).appendTo($('body'))
}

const iteratorUploadObj = function() {
    for (let i = 0; fn = arguments[i++]) {
        const uploadObj = fn()
        if (uploadObj !== false) {
            return uploadObj
        }
    }
}

const uploadObj = iteratorUploadObj(getActiveUploadObj, getFlashUploadObj, getFormUploadObj)

@yaogengzhu
Copy link
Owner Author

yaogengzhu commented Jan 5, 2022

命令模式

用途: 用于执行一个特定事情的指令

const setCommad = function (button, command) {
    button.click = function () {
        command.execute()
    }
}

const MenuBar = {
    refresh: function () {
        console.log('刷新')
    },
}

const SubMenu = {
    add: function () {
        console.log('新增子菜单')
    },

    del: function () {
        console.log('删除子菜单')
    },
}

// 封装命令类
const RefreshMenuCommad = function (recevicer) {
    this.recevicer = recevicer
}

RefreshMenuCommad.prototype.execute = function () {
    this.recevicer.refresh()
}

const AddSubMenuCommand = function (recevicer) {
    this.recevicer = recevicer
}

AddSubMenuCommand.prototype.execute = function () {
    this.recevicer.add()
}

const DelSubMenuCommand = function (recevicer) {
    this.recevicer = recevicer
}

DelSubMenuCommand.prototype.execute = function () {
    // console.log('删除子菜单')
    this.recevicer.del()
}

// 将命令接受者传入到command对象中,并且将command对象安装到button 上

const refreshMenuBarCommand = new RefreshMenuCommad(MenuBar)
const addSubMenuCommand = new AddSubMenuCommand(SubMenu)
const delSubMenuCommand = new DelSubMenuCommand(SubMenu)

setCommad(button1, refreshMenuBarCommand)
setCommad(button2, addSubMenuCommand)
setCommad(button3, delSubMenuCommand)

命令模式应用

// 游戏
const Ryu = {
    attack: function () {
        console.log('攻击')
    },

    defense: function () {
        console.log('防御')
    },

    jump: function () {
        console.log('跳跃')
    },

    crouch: function () {
        console.log('蹲下')
    },
}

// 创建命令
const makeCommand = function (recevicer, state) {
    return function () {
        recevicer[state]()
    }
}

const commands = {
    119: 'jump',
    115: 'crouch',
    97: ' defense',
    100: 'attach',
}

const commandStack = [] // 保存命令栈

document.onKeypress = function (ev) {
    const keyCode = ev.keyCode,
        command = makeCommand(Ryu, commands[keyCode])

    if (command) {
        command()
        commandStack.push(command) // 将刚执行过的命令推到栈里
    }
}

// 点击播放录像
document.getElementById('replay').onclick = function () {
    let command
    while (command === commandStack.shift()) {
        // 从堆栈里一次取出命令并执行
        command()
    }
}

宏命令

宏命令是一组命令的集合,通过执行宏命令,可以支持一次执行一批命令

// 依次创建好各种command

const closeDoorCommand = {
    execute: function () {
        console.log('关门')
    },
}

const openPcCommand = {
    execute: function () {
        console.log('开电脑')
    },
}

const openQQCommand = {
    execute: function () {
        console.log('登QQ')
    },
}

const MaroCommand = function () {
    return {
        commandList: [],
        add: function (command) {
            this.commandList.push(command)
        },
        execute: function () {
            this.commandList.forEach((fn) => fn.execute())
        },
    }
}

const macroCommand = new MaroCommand()

macroCommand.add(closeDoorCommand)
macroCommand.add(openPcCommand)
macroCommand.add(openQQCommand)
macroCommand.execute()

@yaogengzhu
Copy link
Owner Author

职责链模式

定义:使用多个对象处理请求,从而避免请求发送者和接收者之间的耦合关联,将这些对象连成一条链子,并沿着链子传递请求,直到有一个对象处理它为止

/**
 * 普通函数写法
 * @param {*} orderType  订单类型
 * @param {*} pay   是否已支付
 * @param {*} stock 库存数量
 */
const order = function (orderType, pay, stock) {
    if (orderType === 1) {
        if (pay === true) {
            console.log('已付款500元定金,可以得到100优惠券')
        } else {
            if (stock > 0) {
                console.log('普通购买,无优惠券')
            } else {
                console.log('库存不足')
            }
        }
    } else if (orderType === 2) {
        if (pay === true) {
            console.log('已付款200元定金,可以得到50优惠券')
        } else {
            if (stock > 0) {
                console.log('普通购买,无优惠券')
            } else {
                console.log('库存不足')
            }
        }
    } else if (orderType === 3) {
        if (stock > 0) {
            console.log('普通购买,无优惠券')
        } else {
            console.log('库存不足')
        }
    }
}

// order(1, true, 500)

/**
 * 职责链重构
 */
const order500 = function (orderType, pay, stock) {
    if (orderType === 1 && pay === true) {
        console.log('已付款500元定金,可以得到100优惠券')
    } else {
        order200(orderType, pay, stock)
    }
}

const order200 = function (orderType, pay, stock) {
    if (orderType === 2 && pay === true) {
        console.log('已付款200元定金,可以得到50优惠券')
    } else {
        orderNormal(orderType, pay, stock)
    }
}

const orderNormal = function (orderType, pay, stock) {
    if (stock > 0) {
        console.log('普通购买,无优惠券')
    } else {
        console.log('库存不足')
    }
}

// order500(3, true, 500)

/**
 * 升级写法
 */

const Chain = function (fn) {
    this.fn = fn
    this.successor = null // 表示职责链的下一个节点
}

/**
 * 指定在链中的下一个节点
 * @param {*} successor
 * @returns
 */
Chain.prototype.setNextSuccessor = function (successor) {
    return (this.successor = successor)
}

/**
 * 传递请求给某一个节点
 * @returns
 */
Chain.prototype.passRequest = function () {
    let ret = this.fn.apply(this, arguments)
    if (ret === 'nextSuccessor') {
        return (
            this.successor &&
            this.successor.passRequest.apply(this.successor, arguments)
        )
    }

    return ret
}

const upgradeOrder500 = function (orderType, pay, stock) {
    if (orderType === 1 && pay === true) {
        console.log('已付款500元定金,可以得到100优惠券')
    } else {
        return 'nextSuccessor'
    }
}

const upgradeOrder200 = function (orderType, pay, stock) {
    if (orderType === 2 && pay === true) {
        console.log('已付款200元定金,可以得到50优惠券')
    } else {
        return 'nextSuccessor'
    }
}

const upgradeOrderNormal = function (orderType, pay, stock) {
    if (stock > 0) {
        console.log('普通购买,无优惠券')
    } else {
        console.log('库存不足')
    }
}

// 将3个订单的函数分别包装成职责链的节点
const chainOrder500 = new Chain(upgradeOrder500)
const chainOrder200 = new Chain(upgradeOrder200)
const chainNormal = new Chain(upgradeOrderNormal)

// 指定节点在职责链的顺序
chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainNormal)

// 将请求传递给第一个节点
chainOrder500.passRequest(2, true, 500)

@yaogengzhu
Copy link
Owner Author

补充链表结合职责链模式实现

地址

@yaogengzhu
Copy link
Owner Author

适配器模式

用来解决两个软件实体间接口不兼容的问题。

const google = {
  show: function () {
    console.log('渲染goggle地图')
  },
}

const baidu = {
  show: function () {
    console.log('渲染baidu地图')
  },
}

const renderMap = function (map) {
  if (map.show instanceof Function) {
    map.show()
  }
}

renderMap(google)
renderMap(baidu)

/**
 * 异常,不是show
 */
const newBaidu = {
  display: function () {
    console.log('渲染新百度地图')
  },
}

const newBaiduAdapter = {
  // 重新一个写一个方法来适配现有的结构
  show: function () {
    return newBaidu.display()
  },
}

renderMap(newBaiduAdapter)

@yaogengzhu
Copy link
Owner Author

什么是多态

同一操作作用不同的对象上, 可以产生不同的解释和不同的执行结果

function renderMap(map) {
  if (map.show instanceof Function) {
     map.show()
  }
}

class GoogleMap {
  show() {
     console.log('渲染Google地图')
  }
}

class SogoMap {
  show() {
    console.log('渲染Sogo地图')
  }
}

console.log(renderMap(new GoogleMap()))
console.log(renderMap(new SogoMap()))

@yaogengzhu
Copy link
Owner Author

柯里化前置知识

实现一个计算cost(10)、cost(20)、cost(30)、最后通过cost() 得到最终的结果

思路:参数为空时,返回最终结果 可将参数存起来,判断参数为空时 在统计返回结果,需要利用到闭包的知识点;

const cost = (function () {
  const args = []; // 存放参数
  return function () {
    // 判断参数是否为空, 参数为空,则表示需要直接返回最终结果
    if (arguments.length === 0) {
      let momeny = 0;
      for (let i = 0; args.length === 0; i++) {
        momeny += args[i];
      }
      return momeny;
    } else {
      // 如果参数存在,则将参数全部存到args 中
      [].push.apply(args, arguments);
    }
  };
})();

通用方案

const cost = (function () {
  let momeny = 0;
  return function () {
    for (let i = 0; i < arguments.length; i++) {
      momeny += arguments[i];
    }
    return momeny;
  };
})();

function currying(fn) {
  const args = [];
  return function () {
    if (arguments.length == 0) {
      return fn.apply(this, args);
    } else {
      [].push.apply(args, arguments);
      return arguments.callee;
    }
  };
}
const fn = currying(cost);
fn(1)(2);
console.log(fn());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
设计模式 Pull requests that update a dependency file
Projects
None yet
Development

No branches or pull requests

1 participant