设计模式学习(五)

一.职责链模式

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链 传递该请求,直到有一个对象处理它为止。

请求发送者只需要知道链中的第一个节点,弱化发送者和一组接收者之间的强联系,可以便捷地在职责链中增加或删除一个节点,同样地,指定谁是第一个节点也很便捷。

以展示不同类型的变量为例,设置一条职责链,可以免去多重if条件分支。

// 定义链的某一项
function ChainItem(fn) {
    this.fn = fn;
    this.next = null;
}

ChainItem.prototype = {
    constructor: ChainItem,
    
    // 设置下一项
    setNext: function(next) {
        this.next = next;
        return next;
    },
    
    // 开始执行
    start: function() {
        this.fn.apply(this, arguments);
    },
    
    // 转到链的下一项执行
    toNext: function() {
        if (this.next) {
            this.start.apply(this.next, arguments);
        } else {
            console.log('无匹配的执行项目');
        }
    }
};

// 展示数字
function showNumber(num) {
    if (typeof num === 'number') {
        console.log('number', num);
    } else {
        // 转移到下一项
        this.toNext(num);
    }
}

// 展示字符串
function showString(str) {
    if (typeof str === 'string') {
        console.log('string', str);
    } else {
        this.toNext(str);
    }
}

// 展示对象
function showObject(obj) {
    if (typeof obj === 'object') {
        console.log('object', obj);
    } else {
        this.toNext(obj);
    }
}

var chainNumber = new ChainItem(showNumber);
var chainString = new ChainItem(showString);
var chainObject = new ChainItem(showObject);

// 设置链条
chainObject.setNext(chainNumber).setNext(chainString);

chainString.start('12'); // string 12
chainNumber.start({}); // 无匹配的执行项目
chainObject.start({}); // object {}
chainObject.start(123); // number 123

这时想判断未定义的时候呢,直接加到链中即可

// 展示未定义
function showUndefined(obj) {
    if (typeof obj === 'undefined') {
        console.log('undefined');
    } else {
        this.toNext(obj);
    }
}

var chainUndefined = new ChainItem(showUndefined);
chainString.setNext(chainUndefined);

chainNumber.start(); // undefined

由例子可以看到,使用了职责链后,由原本的条件分支换成了很多对象,虽然结构更加清晰了,但在一定程度上可能会影响到性能,所以要注意避免过长的职责链。

二.惰性初始模式

延迟初始化是一种允许我们延迟初始化消耗资源比较大的进程,直到需要他们的时候(才初始化)。这其中的一个例子就是jQuery的.ready()方法,它在DOM节点加载完毕之后会执行一个回调方法。

$( document ).ready( function () {

    //ajax请求不会执行,直到DOM加载完成

    var jqxhr = $.ajax({
      url: "http://domain.com/api/",
      data: "display=latest&order=ascending"
    })
    .done( function( data ) ){
        $(".status").html( "content loaded" );
        console.log( "Data output:" + data );
    });

});

jQuery.fn.ready()底层是通过byjQuery.bindReady()来实现的, 如下所示:

bindReady: function() {
  if ( readyList ) {
    return;
  }

  readyList = jQuery.Callbacks( "once memory" );

  // Catch cases where $(document).ready() is called after the
  // browser event has already occurred.
  if ( document.readyState === "complete" ) {
    // Handle it asynchronously to allow scripts the opportunity to delay ready
    return setTimeout( jQuery.ready, 1 );
  }

  // Mozilla, Opera and webkit support this event
  if ( document.addEventListener ) {
    // Use the handy event callback
    document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

    // A fallback to window.onload, that will always work
    window.addEventListener( "load", jQuery.ready, false );

  // If IE event model is used
  } else if ( document.attachEvent ) {
    // ensure firing before onload,
    // maybe late but safe also for iframes
    document.attachEvent( "onreadystatechange", DOMContentLoaded );

    // A fallback to window.onload, that will always work
    window.attachEvent( "onload", jQuery.ready );

    // If IE and not a frame
    // continually check to see if the document is ready
    var toplevel = false;

    try {
      toplevel = window.frameElement == null;
    } catch(e) {}

    if ( document.documentElement.doScroll && toplevel ) {
      doScrollCheck();
    }
  }
},

即使不直接在jQuery核心文件中使用,有些开发者通过一些插件也可能熟悉懒加载的概念,延迟加载和揽初始化一样有效,它是一种在需要的时候(比如:当用户浏览到了页面底部的时候)才加载页面数据的技术。

你可能感兴趣的:(设计模式,学习,javascript)