JavaScript之观察者模式

本文介绍观察者模式(发布订阅模式)的基本概念与实现原理,通过一个具体的留言统计案例,展示了如何利用观察者模式分离模块间的耦合,实现事件触发与响应。

观察者模式也叫发布订阅模式!,为了解决主体对象与观察者之间功能的耦合。
定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖对象都会收到通知自动更新。

观察者模式主要分为三个步骤:注册、发布、移除。我们一个一个步骤来实现。
我们定义一个容器,再用闭包包起来,防止污染全局变量,里面存放这些方法,以及要观察的事件。

详细解释看注解

 //防止信息队列暴露而被慕改或影响到其他变量
 var Observer = (function () {
     var _messages = {};
     return {
         //注册信息接口
         regist: function (type, fn) {
             //如果此信息不存在则应该创建一个该消息类型
             if (typeof _messages[type] === 'undefined') {
                 //将动作推入到该信息对应的动作执行队列中
                 _messages[type] = [fn];

             } else {
                 _messages[type].push(fn);
             }
         },
         //发布信息接口
         fire: function (type, args) {
             //如果该小心没有被注册,则返回
             if (!_messages[type])
                 return;
             //定义小心信息
             var events = {
                     type: type, //消息类型
                     args: args || {} //消息携带数据
                 },
                 i = 0, //消息动作循环变量
                 len = _messages[type].length; //消息动作长度
             //遍历消息动作
             for (; i < len; i++) {
                 //依次执行注册的消息对应的动作序列
                 _messages[type][i].call(this, events);
             }
         },
         //移除信息接口
         remove: function (type, fn) {
             //如果消息动作队列存在
             if (_message[type] instanceof Array) {
                 //从最后一个消息动作遍历
                 var i = _message[type].length - 1;
                 for (; i >= 0; i--) {
                     //如果存在该动作在消息动作序列中移除相应动作
                     _messages[type][i] === fn && _messages[type].splice(i, 1);
                 }
             }
         }
     }
 })();

上面就是我们定义好的观察者,当我们想要订阅发布某些实例的时候直接调用即可。
接着我们结合实例来看一下这是怎么使用的,例如我们做一个留言并统计浏览数量的小功能

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div>
        <div>
            用户的数量
            <span id="msg_num">0</span>
        </div>
        <ul id="msg">

        </ul>
        <input type="text" id="user_input" />
        <button id="user_submit">提交</button>

    </div>




    <script>
        //防止信息队列暴露而被慕改或影响到其他变量
        var Observer = (function () {
            var _messages = {};
            return {
                //注册信息接口
                regist: function (type, fn) {
                    //如果此信息不存在则应该创建一个该消息类型
                    if (typeof _messages[type] === 'undefined') {
                        //将动作推入到该信息对应的动作执行队列中
                        _messages[type] = [fn];

                    } else {
                        _messages[type].push(fn);
                    }
                },
                //发布信息接口
                fire: function (type, args) {
                    //如果该小心没有被注册,则返回
                    if (!_messages[type])
                        return;
                    //定义小心信息
                    var events = {
                            type: type, //消息类型
                            args: args || {} //消息携带数据
                        },
                        i = 0, //消息动作循环变量
                        len = _messages[type].length; //消息动作长度
                    //遍历消息动作
                    for (; i < len; i++) {
                        //依次执行注册的消息对应的动作序列
                        _messages[type][i].call(this, events);
                    }
                },
                //移除信息接口
                remove: function (type, fn) {
                    //如果消息动作队列存在
                    if (_message[type] instanceof Array) {
                        //从最后一个消息动作遍历
                        var i = _message[type].length - 1;
                        for (; i >= 0; i--) {
                            //如果存在该动作在消息动作序列中移除相应动作
                            _messages[type][i] === fn && _messages[type].splice(i, 1);
                        }
                    }
                }
            }
        })();


        function $(id) {
            return document.getElementById(id);
        }

        (function () {
            //增加一则消息
            function addMsgItem(e) {
                var text = e.args.text, //获取消息中用户添加的文本内容
                    ul = $('msg'),
                    li = document.createElement('li'),
                    span = document.createElement('span');
                span.innerHTML = " 关闭"

                li.innerHTML = text;

                span.onclick = function () { //移除留言
                    ul.removeChild(li);
                    Observer.fire('removeCommentMessage', {
                        num: -1
                    });
                }
                li.appendChild(span);
                ul.appendChild(li);
            }
            Observer.regist('addCommentMessage', addMsgItem); //注册添加评论信息
        })();

        (function () {
            function changeMsgNum(e) {
                var num = e.args.num;
                $('msg_num').innerHTML = parseInt($('msg_num').innerHTML) + num;
            }
            Observer.regist('addCommentMessage', changeMsgNum);
            Observer.regist('removeCommentMessage', changeMsgNum);
        })();

        (function () {
            $('user_submit').onclick = function () {

                var text = $('user_input');
                if (text.value === '') {
                    return;
                }
                Observer.fire('addCommentMessage', {
                    text: text.value,
                    num: 1
                });
                text.value = '';
            }
        })();
    </script>
</body>

</html>

在这个例子中可以看出我们将每个模块抽离了出来,互不关系,完美解决模块间耦合功能。
其使用什么广泛,适用于关联于某些行为场景,并触发一系列事件。例如用来发布消息推送、点击事件侦听等等。。。

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值