JavaScript设计模式你了解多少?(下)

80 阅读6分钟

行为型设计模式

行为型设计模式用于不同对象之间职责划分或算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或对象之间的交流模式并加以实现。

  • 模板方法模式
    模板方法模式( Template Method ):父类中定义一组操作算法骨架,而将一些实现步骤延
    迟到子类中,使得子类可以不改变父类的算法结构的同时可重新定义算法中某些实现步骤。
// 弹框 基础类 弹框基础模板
var Alert = function(data){
    if(!data) return
    this.title = data.title
    this.content = data.content
    this.position = 'center'
    // ...
}
Alert.prototype = {
    init: function(){
    },
    bindEvent: function(){
    },
    hide: function(){},
    show: function(){}
}

// 基于基础弹框的左侧弹框类  弹框具体实现
var LeftAlert = function(data){
    Alert.call(this,data)
    this.position = 'left'
}
LeftAlert.prototype = new Alert()
// 其它基于基础模板的弹框...
  • 观察者模式
    观察者模式( Observer ):又被称作发布-订阅者模式或消息机制,定义了一种依赖关系,
    解决了主体对象与观察者之间功能的耦合。实现模块之间的通信
// 观察者
var Observer = (function(){
    var _message = {}
    return {
        // 注册信息接口
        regist:function(type,fn){
            if(typeof _message[type] === 'undefined'){
                // type 消息不存在
                _message[type] = [fn]
            } else {
                // type 消息存在
                _message[type].push(fn)
            }
        },
        // 发布信息接口
        fire:function(type, args){
            // 消息不存在
            if(!_message[type])
                return
            var events = {
                type,
                args: args || {}
            }
            // 依次执行消息
            for(var i=0,len=_message[type].length;i<len;i++){
                _message[type][i].call(this,events)
            }
        },
        // 移除信息接口
        remove: function(type, fn){
            if(_message[type] instanceof Array){
                var i = _message[type].length - 1
                for(;i>= 0;i--){
                    _message[type][i] === fn && _message[type].splice(i,1)
                }
            }
        }
    }
})();

Observer.regist('test',function(e) {
    console.log(e.type,e.args)
})
Observer.fire('test',{msg:"ceshi"})
  • 状态模式
    态模式(State) 当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来
    像是改变了对象。解决复杂、臃肿的分支判断问题
// 超级马里奥 例子
var ActState = function(){
    var _currentState = {}
    var states = {
        jump: function(){},
        move:function(){},
        shoot: function(){},
        aquat:function(){}
    }
    var Action = {
        changeState: function(){
            var arg = this.arguments
            _currentState = {}
            if(arg.length){
                for(var i=0;i< arg.length;i++){
                    _currentState[arg[i]] = true
                }
            }
            return this
        },
        goes:function(){
            for(var i in _currentState){
                states[i] && states[i]()
            }
            return this
        }
    }
    return {
        change: Action.changeState,
        goes: Action.goes
    }
}

// 使用
ActState().change('move').goes().change('jump','shoot').goes()
  • 策略模式
    策略模式( Strategy ):将定义的 一组算法封装起来,使其相互之间可以替换。封装的算法
    具有一定独立性,不会随客户端变化而变化。
// 价格策略对象
var PriceStrategy = function(){
    // 内置算法对象
    var stragtegy = {
        // 满100 反30
        return30: function(price){},
        return50:function(price){},
        // 打折
        percent90:function(price){},
        percent80:function(price){}
    }
    // 策略算法调用接口
    return function(strg,price){
        return stragtegy[strg]&&stragtegy[strg](price)
    }
}

// 其它应用 jq缓冲动画、表单验证
  • 职责链模式
    职责链模式 (Chain of Responsibility ):解决请求的发送者与请求的接受者之间的稿合,通过职
    责链上的多个对象对分解请求流程,实现请求在多个对象之间的传递一直到最后一个对象完成请求
    的处理。
  • 命令模式
    命令模式( Command ):将请求与实现解耦并封装成独立对象,从而使不同的请求对客户
    端的实现参数化。
  • 访问者模式
    访问者模式( Visitor ):针对于对象结构中的元素,定义在不改变该对象的前提下访问结
    构中元素的新方法。解决数据与数据的操作方法之间的耦合,将数据的操作方法独立与数据
//Object.prototype.toString.call 该方法与操作数据独立

// ie 事件绑定
function bindIEEvent(dom,type,fn,data){
    var data = data || {}
    dom.attachEvent('on'+type,function(e){
        fn.call(dom,e,data)
    })
}

// 访问器
var Visitor = (function(){
    return {
        splice: function(){
            var args = Array.prototype.splice.call(arguments,1)
            return Array.prototype.splice.apply(arguments[0],args)
        },
        push: function(){
            var len = arguments[0].length || 0
            var args = this.splice(arguments,1)
            arguments[0].length = len + arguments.length - 1 //length属性矫正
            return Array.prototype.push.apply(arguments[0],args)
        },
        pop: function(){
            return Array.prototype.pop.apply(arguments[0])
        }
    }
})();
  • 中介者模式
    中介者模式(Mediator ):通过中介者对象封装一系列对象之间的交互,使对象之间不再
    相互引用,降低他们之间的糯合。有时中介者对象也可改变对象之间的交互。
// 中介者对象
var Midiator = function(){
    var _msg = {}
    return {
        register:function(type,fn){
            if(_msg[type]){
                _msg[type].push(fn)
            }else{
                _msg[type] = [fn]
            }
        },
        send: function(type){
            if(_msg[type]){
                for(var i=0,len=_msg[type].length;i<len;i++){
                    _msg[type][i]&&_mas[type][i]()
                }
            }
        }
    }
}();
  • 备忘录模式
    备忘录模式(Memento ):在不破坏对象的封装性的前提下,在对象之外捕获并保存该对
    象内部的状态以便日后对象使用或者对象恢复到以前的某个状态。 解决数据缓存问题
// 页面缓存(分页)
var Page = function(){
    var _cache = {}
    return function(page,fn){
        if(_cache[page]){
            showPage(page,_cache[page])
            fn&&fn()
        }else{
            $.post('getData',{
                page:page
            },(res)=>{
                showPage(page,res.data)
                // 缓存api请求数据
                _cache[page] = res.data
                fn&&fn()
            })
        }
    }
}
  • 迭代器模式
    选代器模式(Iterator ):在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的
    元素。常用于简化循环,减少不必要的循环,提升性能
// 数组迭代器
var eachArr = function(arr,fn){
    var i = 0,len = arr.length
    for(;i<len;i++){
        if(fn.call(arr[i],i,arr[i]) === false){
            break
        }
    }
}


// 同步变量迭代取值器  解决a.b.c中b不存在c报错问题
var AGetter = function(key){
    key = key.split('.')
    var result = key[0]
    if(!result){
        return undefined
    }
    for(var i=1,len = key.length;i<len;i++){
        if(result[key[i]] !== undefined){
            result = result[key[i]]
        }else {
            return undefined
        }
    }
    return result
}
  • 解释器模式
    解释器模式(Interpreter ):对于一种语言,给出其文法表示形式,并定义一种解释器,通
    过使用这种解释器来解释语言中定义的句子。

技巧型设计模式

技巧型设计模式是通过 一些特定技巧来解决组件的某些方面的问题,这类技巧一般通过实践经验总结得到。

  • 链模式

链模式( Operate of Responsibility ):通过在对象方法中将当前对象返回,实现对同一个对
象多个方法的链式调用。从而简化对该对象的多个方法的多次调用时,对该对象的多次引用。

// jquery
var A = function(selector){
    return new A.fn.init(selector)
}
A.fn = A.prototype = {
    // 构造器强化
    constructor: A,
    init: function(selector){
        this[0] = document.querySelector(selector)
        this.length = 1
        return this
    },
    length: 2,
    size: function(){
        return this.length
    }
}
A.fn.init.prototype = A.fn
// 扩展方法
A.extend = A.fn.extend = function(){
    var i = 1,
        len = arguments.length,
        target = arguments[0],
        j;
    if(i == len){
        target = this
        i--
    }
    for(;i<len;i++){
        for(j in arguments[i]) {
            target[j] = arguments[i][j]
        }
    }
    return target
}
// 
A.fn.extend({
    on:(function(){
        // 这里就不考虑兼容性了
        return function(type,fn){
            var i = this.length-1
            for(;i>=0;i--){
                this[i].addEventListener(type,fn,false)
            }
            return this
        }
    })();
})
  • 委托模式

委托模式( Entrust ):多个对象接收井处理同一请求,他们将请求委托给另一个对象统
处理请求。

// dom 中的事件委托
document.getElementByTagName('ul').onclick = function(e) {
    // e.target
}
  • 数据访问对象模式

数据访问对象模式(Data access object-DAO ): 抽象和封装对数据源的访问与存储, DAO通过对数据源链接的管理方便对数据的访问与存储。

  • 节流模式

节流模式(Throttler): 对重复的业务逻辑进行节流控制,执行最后一次操作并取消其他操作,以提高性能。
解决重复触发问题

// 节流器
var throttle = function(){
    var isClear = arguments[0], fn;
    if(typeof isClear === 'boolean') {
        fn = arguments[1]
        fn._throttleID&&clearTimeout(fn._throttleID)
    }else{
        fn = isClear
        params = arguments[1]
        var p = extend({ //
            context:null,
            args:[],
            time:300
        },params)
        arguments.callee(true,fn) // 清除执行函数句柄
        fn._throttleID = setTimeout(function(){
            fn.apply(p.context,p.args)
        },p.time)
    }
}

// 使用
function scrollFn(){

}
window.onscroll = function(){
    throttle(scrollFn)
}
  • 简单模板模式
    简单模板模式( Simple template ):通过格式化字符串拼凑出视图避免创建视图时大量节
    点操作。优化内存开销。
  • 惰性模式
    惰性模式 (layier) :减少每次代码执行时的重复性的分支判断,通过对对象重定义来屏蔽
    原对象中的分支判断。
// 事件绑定兼容处理,只需要执行一次兼容判断
var bindAct = function(dom,type,fn){
    if(dom.addEventListener){
        return function(dom,type,fn){
            dom.addEventListener('on'+type,fn)
        }
    }else if(dom.attachEvent){
        return function(dom,type,fn){
            dom.attachEvent('on'+type,fn)
        }
    }else{
        return function(dom,type,fn){
            dom['on'+type] = fn
        }
    }
}();
  • 参与者模式
    参与者(participator ):在特定的作用域中执行给定的函数,并将参数原封不动地传递
var bind = function(fn,context){
    return function(){
        return fn.apply(context,arguments)
    }
}
var obj = {
    title:'test'
}
var fn = function(){
    console.log(this.title)
}
var bindFn = bind(fn,obj)
fn()  // 输出 undefined
bingFn() //输出  test
  • 等待者模式
    等待者模式(waiter ):通过对多个异步进程监听,来触发未来发生的动作。

架构型设计模式

架构型设计模式是一类框架结构,通过提供一些子系统,指定他们的职责,并将它们条理清晰地组织在一起

模块化:将复杂的系统分解成高内聚、低稿合的模块,使系统开发变得可控、可维护、可
拓展,提高模块的复用率。

  • 同步模块模式
    同步模块模式一-SMD (Synchronous Module Definition ): 请求发出后,无论模块是否
    存在,立即执行后续的逻辑,实现模块开发中对模块的立即引用。
  • 异步模块模式
    异步模块模式一-AMD (Asynchronous Module Definition ): 请求发出后,继续其他业务
    逻辑,知道模块加载完成执行后续的逻辑,实现模块开发中对模块加载完成后的引用。
  • Widget模式
    Widget: (Web Widget 指的是 块可以在任意页面中执行的代码块) Widget 模式是指借用
    Web Widget 思想将页面分解成部件,针对部件开发,最终组合成完整的页面
  • MVC模式

MVC 即模型( model) 一视图( view )一控制器( controller ),用 一种将业务逻辑、数据、
视图分离的方式组织架构代码。

  • MVP模式

MVP 模型( Model) 一视图( View )一管理器( Presenter): View 层不直接引用 Model
层内的数据,而是通过 Presenter 层实现对 Model 层内的数据访问。即所有层次的交互都发生在
Presenter 层中。

  • MVVM模式

MVVM 模式,模型(Model) -视图( View) -视图模型( ViewModel ):为视图层( View)
量身定做 套视图模型( ViewModel) ,井在视图模型( ViewModel) 中创建属性和方法,为视
图层( View )绑定数据( Model) 并实现交互。

注:本文为《JavaScript设计模式》读书笔记,大部分内容来源于该书籍。