最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 设计模式

    正文概述 掘金(murphy_r)   2021-01-28   559
    |- 工厂模式  
    |- 单例模式
    |- 原型模式
    |- 装饰器模式
    |- 代理模式
    |- 策略模式(行为型)
    |- 状态模式(行为型)
    |- 观察者模式(行为型)
    |- 迭代器(行为型)
    

    设计模式原则:

    开放封闭原则的内容:对拓展开放,对内修改封闭

    工厂模式:

    what ?

    将创建对象的过程单独封装,这样的操作就是工厂模式

    • 抽象工厂-> 具体工厂-> 抽象产品 -> 具体产品
    • 抽象工厂是佐证“开放封闭原则”的良好素材
    //工厂模式示例
    function User(name, age, career, work) {
        this.name = name;
        this.age = age;
        this.career = career;
        this.work = work;
    }
    
    function Factory(name, age, career) {
       let work;
       switch(career) {
           case 'coder':
               work = ['写代码'];
               break;
           case 'productor':
               work = ['生产'];
               break;
           ...
           
       }
       return new User(name, age, career, work)
        
    }
    
    

    单例模式

    what ?

    • 保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式
    • 唯一数据源 (SSOT)

    how ?

    • eg: 在vuex中的应用:一个 Vue 实例只能对应一个 Store
    Vue.use(Vuex); 只注入一次vue的实例只会install一次vuex插件,保证store的唯一性
    

    demo

    • 利用静态static 方法可以创建单例模式
    class SingleSong {
        show() { console.log('sing....') }
        static getInstance() {
            if(!SingleSong.instance) {
                SingleSong.instance = new SingleSong();
            }
            return SingleSong.instance;
        }
    }
    // 方法2: 利用闭包创建单例
    SingleSong.getInstance = (function(){
        let instance = null;
        return function() {
            if(!instance) {
                instance = new SingleSong();
            }
            return instance;
        }
    })()
    
    • 利用闭包创建一个单例模式modal
    
      const Modal = (function() {
        	let modal = null
        	return function() {
                if(!modal) {
                	modal = document.createElement('div')
                	modal.innerHTML = '您还未登录哦~'
                	modal.id = 'modal'
                	modal.style.display = 'none'
                	document.body.appendChild(modal)
                }
                return modal
        	}
        })()
        
        const modal = new Modal()
    
    • 面试题: 实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)。
    // 方法一:es6 
    class Storage {
        static getIns() {
            if(!Storage.instance) {
                Storage.instance = new Storage();
            }
            return Storage.instance;
        }
        getItem(key) {
            return localStorage.getItem(key)
        }
        setItem(key, value) {
            localStrage.setItem(key, value)
        }
    }
    // 方法二:
    function StorageBase() {}
    Storage.prototype.getItem = function(key) { return localStorage.getItem(key)}
    Storage.prototype.setItem = function(key, value) {  localStrage.setItem(key, value)}
    const Storage = (function(){
        let instance = null;
        return function() {
            if(!instance) {
                instance = new StorageBase();
            }
            return instance;
        }
    })()
    

    原型模式

    • JavaScript 这门语言面向对象系统的根本

    装饰器模式:

    what ?

    • 装饰器模式,又名装饰者模式。它的定义是“在不改变原对象的基础上,通过对其进行包装拓展,使原有对象可以满足用户的更复杂需求”
    • 实例是在我们的代码运行时动态生成的,而装饰器函数则是在编译阶段就执行了。所以说装饰器函数真正能触及到的,就只有类这个层面上的对象

    how ?

    • HOC 、 redux、axios 中的应用
    • HOC (Higher Order Component) 即高阶组件。它是装饰器模式在 React 中的实践
    // react 中的高阶组件:
    import React, { Component } from 'react'
    
    const BorderHoc = WrappedComponent => class extends Component {
      render() {
        return <div style={{ border: 'solid 1px red' }}>
          <WrappedComponent />
        </div>
      }
    }
    export default borderHoc
    

    demo

    // 定义打开按钮
    class OpenButton {
        // 点击后展示弹框(旧逻辑)
        onClick() {
            const modal = new Modal()
        	modal.style.display = 'block'
        }
    }
    
    // 定义按钮对应的装饰器
    class Decorator {
        // 将按钮实例传入
        // 重点:
        constructor(open_button) {
            this.open_button = open_button
        }
        
        onClick() {
            this.open_button.onClick()
            // “包装”了一层新逻辑
            this.changeButtonStatus()
        }
        
        changeButtonStatus() {
            this.changeButtonText()
            this.disableButton()
        }
        // 单一职责
        disableButton() {
            const btn =  document.getElementById('open')
            btn.setAttribute("disabled", true)
        }
        // 单一职责
        changeButtonText() {
            const btn = document.getElementById('open')
            btn.innerText = '快去登录'
        }
    }
    
    装饰器在redux中的应用:
     
    import { connect } from 'react-redux';
    import { bindActionCreators } from 'redux';
    import action from './action.js';
    
    function mapStateToProps(state){
        return state.app;
    }
    function mapDispatchToProps(dispatch) {
        return bindActionCreators(action, dispatch);
    }
    export default connect(mapStateToProps, mapDispatchToProps);
    
    

    axios 中的适配器

    • axios本身就用到了我们的适配器模式
    • 这正是一个好的适配器的自我修养——把变化留给自己,把统一留给用户
    // 用fetch封装一个HttpUtils:
    export default class HttpUtils{
        // get请求
        static get(url)
            return new Promise((resolve, reject) => {
                fetch(url)
                    .then(result => {
                        resolve(result);
                    })
                    .catch(err => {
                        reject(err);
                    })
            })
        // post请求
        static post(url, data){
            return new Promise((resolve, reject) => {
                fetch(url, {
                    method: 'POST',
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: this.changeData(data)
                })
                .then(response => response.json())
                .then(result => {
                    resolve(result);
                })
                .catch(err => {
                    reject(err);
                })
            }
        }
        // body请求体的格式化方法
          static changeData(obj) {
            var prop,
              str = ''
            var i = 0
            for (prop in obj) {
              if (!prop) {
                return
              }
              if (i == 0) {
                str += prop + '=' + obj[prop]
              } else {
                str += '&' + prop + '=' + obj[prop]
              }
              i++
            }
            return str
          }
    }
    

    代理模式

    how ?

    • proxy, 缓存

    Proxy

    es6中的代理:new Proxy(obj, {
        get: function(){},
        set: function(){}
    })
    

    缓存代理:

    function addAll(){
        let result = 0;
        const let = arguments.length;
        for(let i =0 ;i < len; i++) {
            result += arguments[i];
        }
        return result;
    }
    
    const proxyAddAll = (function(){
        const resultCache = {};
        return function(){
            //所有参数转换为字符串
            let args = Array.prototype.join.call(arguments, ',');
            if(args in resultCache) {
                return resultCache[args];
            }
            return resultCache[args] = addAll(...arguments);
        }
    })()
    

    行为型-策略模式:

    • 对算法的封装,不依赖于主体
    // 定义一个询价处理器对象
    const priceProcessor = {
      pre(originPrice) {
        if (originPrice >= 100) {
          return originPrice - 20;
        }
        return originPrice * 0.9;
      },
      onSale(originPrice) {
        if (originPrice >= 100) {
          return originPrice - 30;
        }
        return originPrice * 0.8;
      },
      back(originPrice) {
        if (originPrice >= 200) {
          return originPrice - 50;
        }
        return originPrice;
      },
      fresh(originPrice) {
        return originPrice * 0.5;
      },
    };
    

    行为型-状态模式:

    状态模式主要解决的是当控制一个对象++状态的条件表达式过于复杂时++的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

    • 指责分离
    • 开放封闭
    • 主体关联
    class CoffeeMaker {
      constructor() {
        // 这里略去咖啡机中与咖啡状态切换无关的一些初始化逻辑
      
        // 初始化状态,没有切换任何咖啡模式
        this.state = 'init';
        // 初始化牛奶的存储量
        this.leftMilk = '500ml';
      }
      stateToProcessor = {
        that: this, // 重点!!!
        american() {
          // 尝试在行为函数里拿到咖啡机实例的信息并输出
          console.log('咖啡机现在的牛奶存储量是:', this.that.leftMilk)
          console.log('我只吐黑咖啡');
        },
        latte() {
          this.american()
          console.log('加点奶');
        },
        vanillaLatte() {
          this.latte();
          console.log('再加香草糖浆');
        },
        mocha() {
          this.latte();
          console.log('再加巧克力');
        }
      }
    
      // 关注咖啡机状态切换函数
      changeState(state) {
        this.state = state;
        if (!this.stateToProcessor[state]) {
          return;
        }
        this.stateToProcessor[state]();
      }
    
    
      latteProcress() {
        this.americanProcess();
        console.log('加点奶');
      }
    
      vanillaLatteProcress() {
        this.latteProcress();
        console.log('再加香草糖浆');
      }
    
      mochaProcress() {
        this.latteProcress();
        console.log('再加巧克力');
      }
    }
    
    const mk = new CoffeeMaker();
    mk.changeState('latte');
    

    行为型:观察者模式

    • 角色划分 --> 状态变化 --> 发布者通知到订阅者,这就是观察者模式的“套路”
    • Event Bus/ Event Emitter
    
    class EventEmitter {
        constructor(){
            // handlers是一个map,用于存储事件与回调之间的对应关系
            this.handlers = {}
        }
        on(eventName, cb) {
            if(!this.handlers[eventName]) {
                // 初始化事件为空数组
                this.handlers[eventName] = []
            }
            // 把回调函数推入目标事件的监听函数队列里去
            this.handler[eventName].push(cb);
        }
        // emit方法用于触发目标事件,它接受事件名和监听函数入参作为参数
        emit(eventName, ...args){
            if(this.handler[eventName]){
                 // 如果有,则逐个调用队列里的回调函数
                this.handlers[eventName].forEach(callback => {
                    callback(...args);
                })
            }
        }
        // 移除某个事件回调队列里的指定回调函数
        // 一个监听事件可以对应多个回调函数
        off(eventName, cb) {
            const cbs = this.handles[eventName];
            const index = cbs.indexOf(cb);
            if(index !== -1) {
                cbs.splice(index,1)
            }
        }
        // 为事件注册单次监听器
        once(eventName, cb) {
         // 对回调函数进行包装,使其执行完毕自动被移除
            const wrapper = (...args) => {
                cb.apply( ...args);
               // 注意!!
                this.off(eventName, warpper);
            }
            this.on(eventName, wrapper);
        }
        
    }
    
    
    • 观察者模式是只有发布者和订阅者。
    • 发布-订阅模式是有中间机构——事件中心,实现了发布者和订阅者的完全解耦。

    行为型:迭代器

    • forEach无法遍历类数组(dom节点数组)
    • 通用遍历方法:for...of...
    • es6:只要具备Symbol.iterator属性就可以被遍历。

    书籍:

    • head first 设计模式
    • 设计模式:可复用面向对象软件的基础

    下载网 » 设计模式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元