zoukankan      html  css  js  c++  java
  • Javascript乱弹设计模式系列(1) - 观察者模式(Observer)

    前言

    博客园谈设计模式的文章很多,我也受益匪浅,包括TerryLee吕震宇等等的.NET设计模式系列文章,强烈推荐。对于我,擅长于前台代码的开发,对于设计模式也有一定的了解,于是我想结合Javascript来设计前台方面的“设计模式”,以对后台“设计模式”做个补充。开始这个系列我也诚惶诚恐,怕自己写得不好,不过我也想做个尝试,一来希望能给一些人有些帮助吧,二来从写文章中锻炼下自己,三来通过写文章对自己增加自信;如果写得不好,欢迎拍砖,我会虚心向博客园高手牛人们学习请教;如果觉得写得还可以,谢谢大家的支持了:)

    这篇将介绍观察者模式。

    概述

    在现实生活中,存在着“通知依赖关系”,如在报纸订阅的服务,只要读者(订阅者)订购了《程序员》的期刊杂志,那么他就订阅了这个服务,他时刻“监听”着邮递员(出版者)来投递报纸给他们,而邮递员(出版者)只要报社有新刊杂志传达给他(就是状态发生了变化),邮递员(出版者)就随时投递(通知)订阅了服务的读者;另一方面,如果读者不想在继续订购(取消通知)《程序员》的杂志了,那么邮递员就不在投递(通知)这些读者了。---这就是典型的出版者和订阅者的关系,而这个关系用一个公式来概括:

    出版者 + 订阅者 = 观察者模式

    定义

    观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。

    类图

    示例分析

    现在开始利用观察者模式来应用到项目的一个场景中去,并且层层剖析一下。

    有这样一个场景,一个购书网站,用户提交上去一个订单,网站系统只要有订单上来,会采取如下操作:(为了简化,我这里其实只是简单的提交)

    一、产生一条通知用户“已购买”记录的短信息(该短信箱还会有其他记录,如交友等等);

    二、在浏览器上显示你的订单名片;

    三、该条订单提交上服务器,保存到数据库或者其它任何存储介质中去,最后显示你的购书记录;

    那么开始我的设计:

    1. 网站上添加IPublisher.js,它作为系统的出版者“接口”,利用第0篇文章面向对象基础以及接口和继承类的实现中的Interface.js类(另外,谢谢winter-cn园友提出了些宝贵的建议,目前Interface类还在改善中,这里暂且先用原来的Interface类:

    这里是改进的程序示范,包括重载函数的构造,这里也暂时贴出来下:

    改进的代码

    调用如下:

    调用方法

    --------------------

    var IPublisher = new Interface('IPublisher', [['registerSubscriber',1], ['removeSubscriber',1], ['notifySubscribers']]);

    所有的依赖者(订阅者)将要注册于它的实现类。

    2. 添加ISubscriber.js,它作为系统的订阅者“接口”:

    var ISubscriber = new Interface('ISubscriber',[['update',4]]);


    3. 现在开始实现我们的IPublisher的具体类,添加OrderData.js,它作为一个订单数据类,让其继承IPublisher的接口:

    function OrderData() {  
        
    this._subscribers = new Array();  //观察者列表
        this.ProductName = "";          //商品名称
        this.ProductPrice = 0.0;        //商品价格
        this.Recommend = 0;             //推荐指数
        this.productCount = 0;          //购买个数
        Interface.registerImplements(this, IPublisher);
    }

    OrderData.prototype 
    = {
        registerSubscriber : 
    function(subscriber) { //注册订阅者
            this._subscribers.push(subscriber);
        },
        removeSubscriber : 
    function(subscriber) {   //删除指定订阅者
            var i = _subscribers.indexOf(subscriber);
            
    if(i > 0)
                _subscribers.slice(i,
    1);
        },
        notifySubscribers : 
    function() {  //通知各个订阅者
            for(var i = 0; i < this._subscribers.length; i++)
            {
                
    this._subscribers[i].update(this.ProductName, this.ProductPrice, this.Recommend, this.ProductCount);
            }
        },
        SubmitOrder : 
    function(productName,productPrice,recommend,productCount) {   //提交订单
            this.ProductName = productName;
            
    this.ProductPrice = productPrice;
            
    this.Recommend = recommend;
            
    this.ProductCount = productCount;
            
    this.notifySubscribers();
        }
    }

    这里简单介绍下,OrderData构造函数中设置订阅者列表,以及商品属性;

    Interface.registerImplements(this, IPublisher);  实际上是让OrderData继承IPublisher接口;

    registerSubscriber,removeSubscriber,notifySubscribers实际上覆盖了从IPublisher继承上来的“接口”方法,这样保存了这个类的方法调用,其中notifySubscribers为通知所有的订阅者更新信息;

    4. 实现ISubscriber的具体类,添加Subscriber.js,它里面包含三个订阅者,1)MsgBox类,短信箱列表;2)ThisOrder类,该条订单名片;3)OrderList类,我的订单列表;并且让其三都继承ISubscriber的“接口”:

    function MsgBox(publisher)
    {
        
    this.Publisher= publisher;
        
    this.Publisher.registerSubscriber(this);
        Interface.registerImplements(
    this, ISubscriber);

    MsgBox.prototype.update 
    = function(productName,productPrice,recommend,productCount) {
    //    具体实现


      
    function ThisOrder(publisher)
    {   
        
    this.Publisher = publisher;
        
    this.Publisher.registerPublisher(this);
        Interface.registerImplements(
    this, ISubscriber);

    ThisOrder.prototype.update 
    = function(productName,productPrice,recommend,productCount) { 
    //    具体实现


      
    function OrderList(publisher)
    {
        
    this.Publisher = publisher;
        
    this.Publisher.registerPublisher(this);
        Interface.registerImplements(
    this, ISubscriber);

    OrderList.prototype.update 
    = function(productName,productPrice,recommend,productCount) { 
    //    具体实现


    看到Subscriber实现类们的构造函数中的内容了么?它把出版者类参数赋值于Subscriber实现类们的Publisher对象,然后在该对象上注册this订阅者自己,这样Publisher对象上就注册了Subscriber对象,并且以Array对象的方式存储起来;

    5. 好了,IPublisher.js,ISubscriber.js,OrderData.js,Subscriber.js都创建好了,现在需要一个aspx界面来使用它们了:

    <div id="Container">
        
    <table width="600px" cellpadding="0" cellspacing="1" class="grid">
            
    <thead>
                
    <tr>
                    
    <th>
                        商品名
                    
    </th>
                    
    <th>
                        市场价
                    
    </th>
                    
    <th>
                        推荐指数
                    
    </th>
                    
    <th>
                        数量
                    
    </th>
                
    </tr>
            
    </thead>
            
    <tbody>
                
    <tr>
                    
    <td>
                        
    <span id="productName">你必须知道的.NET</span>
                    
    </td>
                    
    <td align="center">
                        
    <span id="productPrice">69.8</span>
                    
    </td>
                    
    <td align="center">
                        
    <span id="recommend">10</span>
                    
    </td>
                    
    <td align="center">
                        
    <span id="productCount">1</span>
                    
    </td>
                
    </tr>
            
    </tbody>
            
    <tfoot>
                
    <tr>
                    
    <td align="right" colspan="4">
                        
    <input type="button" id="btnSubmit" value=" 结 算 " />
                    
    </td>
                
    </tr>
            
    </tfoot>
        
    </table>
    </div>
    <div style=" 1000px;">
        
    <div id="MsgBoxContainer">
            
    <h2>
                您的短信箱
    </h2>
            
    <table width="100%" cellspacing="1" cellpadding="0" class="grid">
                
    <thead>
                    
    <tr>
                        
    <th>
                            内容
                        
    </th>
                        
    <th style=" 100px;">
                            发布日期
                        
    </th>
                    
    </tr>
                
    </thead>
                
    <tbody id="MsgBoxResult">
                
    </tbody>
            
    </table>
        
    </div>
        
    <div id="ThisOrderContainer">
            
    <h2>
                您刚提交的订单名片
    </h2>
            
    <div id="ThisOrderResult">
            
    </div>
        
    </div>
        
    <div id="OrderListContainer">
            
    <h2>
                您已买的商品列表
    </h2>
            
    <table width="100%" cellspacing="1" cellpadding="0" class="grid">
                
    <thead>
                    
    <tr>
                        
    <th>
                            商品名
                        
    </th>
                        
    <th>
                            市场价
                        
    </th>
                        
    <th>
                            推荐指数
                        
    </th>
                        
    <th>
                            数量
                        
    </th>
                        
    <th style=" 100px;">
                            发布日期
                        
    </th>
                    
    </tr>
                
    </thead>
                
    <tbody id="OrderListResult">
                
    </tbody>
            
    </table>
        
    </div>
        
    <div class="clear">
        
    </div>
    </div>

    6. 创建一个OrderSend.js,编写相关的JS代码了,以下是核心代码:

    $("#btnSubmit").click(function(){
        
    var productName = $("#productName").html();
        
    var productPrice = parseFloat($("#productPrice").html());
        
    var recommend = parseInt($("#recommend").html());
        
    var productCount = parseInt($("#productCount").html());


        
    var orderData = new OrderData();            //实例化Publisher的实现类orderData
        var msgBox = new MsgBox(orderData);         //orderData作为MsgBox构造函数的参数进行传递 
        var thisOrder = new ThisOrder(orderData);   //orderData作为ThisOrder构造函数的参数进行传递 
        var orderList = new OrderList(orderData);   //orderData作为OrderList构造函数的参数进行传递 
        orderData.SubmitOrder(productName,productPrice,recommend,productCount);     //提交相关商品信息
    });

    通过点击页面上的“提交”,将三个Subscriber实现类注册到OrderData(Publisher实现类)中去,这样只要OrderData对象提交新商品信息上去,也就是状态更新,那么三个Subscriber实现类就会被通知而更新自身相关的内容了。

    页面实现效果如下:

    点击“结算”按钮,如下:

    这里只是简单的对于三个Subscriber进行更新,关于update方法中的实现,这里不在贴出来了,具体可以下载源代码查看看;在update方法中可以编写你想要的操作以及显示结果,如利用$.ajax进行数据操作和数据展示,这里就留着大家自己发挥吧:)

    总结

    该篇文章用Javascript来设计观察者模式的思路,通过触发变化通知的方式来请求状态更新,利用一个简单的购书网站来实践。

    本篇到此为止,谢谢大家阅读

    附:相关源代码下载

     
    参考文献:《Head First Design Pattern》
    本系列文章转载时请注明出处,谢谢合作!

     相关系列文章:
    Javascript乱弹设计模式系列(6) - 单件模式(Singleton)
    Javascript乱弹设计模式系列(5) - 命令模式(Command)
    Javascript乱弹设计模式系列(4) - 组合模式(Composite)
    Javascript乱弹设计模式系列(3) - 装饰者模式(Decorator)
    Javascript乱弹设计模式系列(2) - 抽象工厂以及工厂方法模式(Factory)
    Javascript乱弹设计模式系列(1) - 观察者模式(Observer)
    Javascript乱弹设计模式系列(0) - 面向对象基础以及接口和继承类的实现

  • 相关阅读:
    【python-plt】二元正态密度函数图像
    【python-plt】一元正态分布图像
    【7】极大似然估计与贝叶斯估计
    实变函数【1】集合
    图形学-心得
    分布式网络架构
    shader的内置变量
    图形学-绘制
    python加载图片
    linux下批量删除utf8 bom
  • 原文地址:https://www.cnblogs.com/liping13599168/p/1366599.html
Copyright © 2011-2022 走看看