whkl/blog

对js设计模式的理解

whkl opened this issue · 0 comments

whkl commented

策略模式

  • 使用场景
    要达到某一个目的,根据具体的实际情况,选择合适的方法。适合于实现某一个功能有多种方案可以选择的情景。
    主要用在表单的验证
    ps 网上简短例子
    根据员工薪水salary、绩效等级S、A、B、C,来计算年终奖
// 策略组
var strategies = {
    "S": function(salary){
        return salary * 4;
    },
    "A": function(salary){
        return salary * 3;
    },
    "B":function(salary){
        return salary * 2
    }
};

// 内容组
var calculateBonus = function(level,salary){
    return strategies[level](salary);
}

// 执行
console.log(calculateBonus('S',20000)); // 输出:80000
console.log(calculateBonus('A',10000)); // 输出:30000

*策略模式的优点

  1. 策略模式利用组合,委托等技术和**,有效的避免很多if条件语句。

  2. 策略模式提供了开放-封闭原则,使代码更容易理解和扩展。

  3. 策略模式中的代码可以复用。

单体模式

  • 定义
    单体是一个用来划分命名空间并将一批相关方法和属性组织在一起的对象。它可以被实例化,那么它只能被实例化一次。
  • 使用场景
    用于创建独一无二的,只能有一个实例的对象,单体模式给了我们一个全局的访问点,和全局变量一样方便又没有全局变量的缺点。

最简单的单体实际上就是一个字面量。它把一批有关联的方法和属性组织在一起:
严格来说他也不算一个单体,因为不可以实例化,单体可以实例化,且只能实例化一次

var Singleton = {
    attribute1 : true,
    attribute2 : 10,

    method1 : function(){

    },
    method2 : function(){

    }
};
  • 单体模式的demo
    我们明白的是单体模式如果有实例化的话,那么只实例化一次,要实现一个单体模式的话,我们无非就是使用一个变量来标识该类是否被实例化,如果未被实例化的话,那么我们可以实例化一次,否则的话,直接返回已经被实例化的对象。
// 单体模式
var Singleton = function(name){
    this.name = name;
};
Singleton.prototype.getName = function(){
    return this.name;
}
// 获取实例对象
var getInstance = (function() {
    var instance = null;
    return function(name) {
        if(!instance) {
            instance = new Singleton(name);
        }
        return instance;
    }
})();
// 测试单体模式的实例
var a = getInstance("aa");
var b = getInstance("bb");
console.log(a === b); // true

console.log(a.getName());// aa

console.log(b.getName());// aa
  • 单体模式的优点
    单体模式的好处在于对代码的组织作用。把相关方法和属性组织在一个不会被多次实例化的单体中,可以让代码的调试和维护变得更轻松。描述性的命名空间还可以增强代码的自我说明性,有利于阅读。把方法包裹在单体中,可以防止他们被其他程序员误改。单体最好还是留给定义命名空间和实现分支型方法的这些用途。

迭代器模式

  • 提供一个api来遍历或者操纵复杂的自定义数据结构
    *一般的迭代,我们至少要有2个方法,hasNext()和Next(),这样才做做到遍历所有对象
    ps 书上的一个小demo
var agg = (function () {
    var index = 0,
    data = [1, 2, 3, 4, 5],
    length = data.length;

    return {
        next: function () {
            var element;
            if (!this.hasNext()) {
                return null;
            }
            element = data[index];
            index = index + 2;
            return element;
        },

        hasNext: function () {
            return index < length;
        },

        rewind: function () {
            index = 0;
        },

        current: function () {
            return data[index];
        }

    };
} ());

使用方法

// 迭代的结果是:1,3,5
while (agg.hasNext()) {
    console.log(agg.next());
}
  • 迭代器模式的优点
    迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。
  • js数组的迭代器方法
    some every foreach map filter reduce
    还有jquery中的each
    这些都属于内部迭代器

观察者模式

通过创建“可观察的”对象,当发生一个感兴趣的时间时可将该事件通告给所有观察者,从而形成松散耦合
观察者模式的个人了解

var pubsub = {};
(function (q) {

    var topics = {}, // 回调函数存放的数组
        subUid = -1;
    // 发布方法
    q.publish = function (topic, args) {

        if (!topics[topic]) {
            return false;
        }

        setTimeout(function () {
            var subscribers = topics[topic],
                len = subscribers ? subscribers.length : 0;

            while (len--) {  //遍历订阅的用户,每个人都发布消息
                console.log(`${subscribers[len].token}:订阅了${topic},所以我会发送这个给他`);
                subscribers[len].func(topic, args);
            }
        }, 0);

        return true;

    };
    //订阅方法
    q.subscribe = function (username, topic, func) {

        if (!topics[topic]) {
            topics[topic] = [];
        }

        var token = username;
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };
    //退订方法
    q.unsubscribe = function (token) {
        for (var m in topics) {
            if (topics[m]) {
                for (var i = 0, j = topics[m].length; i < j; i++) {
                    if (topics[m][i].token === token) {
                        topics[m].splice(i, 1);
                        return token;
                    }
                }
            }
        }
        return false;
    };
} (pubsub))

调用

pubsub.subscribe('zhaomei','example1', function (topics, data) {   //用户zhaomei订阅了 example1这个话题
    console.log(topics + ": " + data);
});
pubsub.publish('example1', 'hello world!');// 发布example1这个话题
//=>zhaomei:订阅了example1,所有我会发送这个给他
//=>example1: hello world!