[js高手之路]设计模式系列课程-发布者,订阅者重构购物车

来源:互联网 发布:岳阳蔬菜网络销售 编辑:程序博客网 时间:2024/05/22 17:09

发布者订阅者模式,是一种很常见的模式,比如:

一、买卖房子

生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色

中介拿到卖主的房源信息,根据手头上掌握的客户联系信息(买房的人的手机号),通知买房的人,他充当了发布者的角色

卖主想卖掉自己的房子,就需要告诉中介,把信息交给中介发布

二,网站订阅信息的用户

订阅者角色:需要订阅某类信息的网民,如某个网站的javascript类型文章

发布者角色:邮箱服务器,根据网站收集到的用户订阅邮箱,通知用户.

网站主想把信息告诉订阅者,需要把文章相关内容告诉邮箱服务器去发送

等等非常多的例子,不一一列举

本文用网站订阅的方式,推导发布者-订阅者框架,然后用发布者-订阅者框架来重构一个简单的购物车

 1         var Site = {}; 2         Site.userList = []; 3         Site.subscribe = function( fn ){ 4             this.userList.push( fn ); 5         } 6         Site.publish = function(){ 7            for( var i = 0, len = this.userList.length; i < len; i++ ){ 8                 this.userList[i].apply( this, arguments ); 9            } 10         }11         Site.subscribe( function( type ){12             console.log( "网站发布了" + type + "内容" );13         });14         Site.subscribe( function( type ){15             console.log( "网站发布了" + type + "内容" );16         });17         Site.publish( 'javascript' );18         Site.publish( 'html5' );

Site.userList就是用来保存订阅者

Site.subscribe就是具体的订阅者,把每一个订阅者订阅的具体信息保存在Site.userList

Site.publish就是发布者:根据保存的userList,一个个遍历(通知),执行里面的业务逻辑

但是这个,发布订阅者模式,有个问题,不能订阅想要的类型,上例我加了2个订阅者(第11行,第14行),只要网站发了信息,全部能收到,但是有些用户可能只想收到javascript或者html5的,所以,接下来,我们需要继续完善,希望能够接收到具体的信息,不是某人订阅的类型,就不接收

 1         var Site = {}; 2         Site.userList = {}; 3         Site.subscribe = function (key, fn) { 4             if (!this.userList[key]) { 5                 this.userList[key] = []; 6             } 7             this.userList[key].push(fn); 8         } 9         Site.publish = function () {10             var key = Array.prototype.shift.apply(arguments),11                 fns = this.userList[key];12             if ( !fns || fns.length === 0) {13                 console.log( '没有人订阅' + key + "这个分类的文章" );14                 return false;15             }16             for (var i = 0, len = fns.length; i < len; i++) {17                 fns[i].apply(this, arguments);18             }19         }20 21         Site.subscribe( "javascript", function( title ){22             console.log( title );23         });24 25         Site.subscribe( "es6", function( title ){26             console.log( title );27         });28 29         Site.publish( "javascript", "[js高手之路]寄生组合式继承的优势" );30         Site.publish( "es6", "[js高手之路]es6系列教程 - var, let, const详解" );31         Site.publish( "html5", "html5新的语义化标签" );

输出结果:

[js高手之路]寄生组合式继承的优势

[js高手之路]es6系列教程 - var, let, const详解

没有人订阅html5这个分类的文章

我们可以看到,只有订阅了javascript类型文章的人,才能收到 ”寄生组合式继承的优势” 这篇文章,发布html5类型的时候,没有任何人会收到.

es6类型的,只有订阅es6的人,才能收到

我们已经有了一个基本的发布订阅者框架,接下来,把他完善成一个框架,便于其他功能或者其他网站系统的相同功能可以重用他

        var Event = {            userList : {},            subscribe : function (key, fn) {                if (!this.userList[key]) {                    this.userList[key] = [];                }                this.userList[key].push(fn);            },            publish : function () {                var key = Array.prototype.shift.apply(arguments),                    fns = this.userList[key];                if (!fns || fns.length === 0) {                    console.log('没有人订阅' + key + "这个分类的文章");                    return false;                }                for (var i = 0, len = fns.length; i < len; i++) {                    fns[i].apply(this, arguments);                }            }        };        var extend = function( dstObj, srcObj ){            for( var key in srcObj ){                dstObj[key] = srcObj[key];            }        }        var Site = {};        extend( Site, Event );         Site.subscribe( "javascript", function( title ){            console.log( title );        });        Site.subscribe( "es6", function( title ){            console.log( title );        });        Site.publish( "javascript", "寄生组合式继承的优势" );        Site.publish( "es6", "es6系列教程 - var, let, const详解" );        Site.publish( "html5", "html5新的语义化标签" );

然后,我们来重构一个购物车实例,没有重构之前,我的购物车用的是面向过程:

 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4     <meta charset="UTF-8"> 5     <title>Title</title> 6     <script src="js/cart.js"></script> 7 </head> 8 <body> 9 <div >10     <ul>11         <li>12             <input type="button" value="-">13             <span class="num">0</span>14             <input type="button" value="+">15             <span>单价:</span>16             <span class="unit">15元;</span>17             <span class="label">小计:</span>18             <span class="subtotal">0</span>元19         </li>20         <li>21             <input type="button" value="-">22             <span class="num">0</span>23             <input type="button" value="+">24             <span>单价:</span>25             <span class="unit">10元;</span>26             <span class="label">小计:</span>27             <span class="subtotal">0</span>元28         </li>29         <li>30             <input type="button" value="-">31             <span class="num">0</span>32             <input type="button" value="+">33             <span>单价:</span>34             <span class="unit">5元;</span>35             <span class="label">小计:</span>36             <span class="subtotal">0</span>元37         </li>38         <li>39             <input type="button" value="-">40             <span class="num">0</span>41             <input type="button" value="+">42             <span>单价:</span>43             <span class="unit">2元;</span>44             <span class="label">小计:</span>45             <span class="subtotal">0</span>元46         </li>47         <li>48             <input type="button" value="-">49             <span class="num">0</span>50             <input type="button" value="+">51             <span>单价:</span>52             <span class="unit">1元;</span>53             <span class="label">小计:</span>54             <span class="subtotal">0</span>元55         </li>56     </ul>57     <div class="total-box">58         商品一共59         <span >0</span>60         件;61         一共花费62         <span >0</span>63         元;64         其中最贵的商品单价是<span >0</span>元65     </div>66 </div>67 </body>68 </html>

cart.js文件:

 1 function getByClass(cName, obj) { 2     var o = null; 3     if (arguments.length == 2) { 4         o = obj; 5     } else { 6         o = document; 7     } 8     var allNode = o.getElementsByTagName("*"); 9     var aNode = [];10     for( var i = 0 ; i < allNode.length; i++ ){11        if( allNode[i].className == cName ){12           aNode.push( allNode[i] );13        }14     }15     return aNode;16 }17 18 function getSubTotal( unitPrice, goodsNum ){19     return unitPrice * goodsNum;20 }21 22 function getSum(){ //计算总花费23     var aSubtotal = getByClass("subtotal");24     var res = 0;25     for( var i = 0; i < aSubtotal.length; i++ ){26        res += parseInt(aSubtotal[i].innerHTML);27     }28     return res;29 }30 31 function compareUnit() { //比单价,找出最高的单价32     var aNum = getByClass( "num");33     var aUnit = getByClass( "unit");34     var temp = 0;35     for( var i = 0; i < aNum.length; i++ ){36        if( parseInt(aNum[i].innerHTML) != 0 ){37             if( temp < parseInt(aUnit[i].innerHTML) ) {38                temp = parseInt(aUnit[i].innerHTML);39             }40        }41     }42     return temp;43 }44 45 window.onload = function () {46     var aInput = document.getElementsByTagName("input");47     var total = 0;48     var oGoodsNum = document.getElementById("goods-num");49     var oTotalPrice = document.getElementById("total-price");50     var oUnitPrice = document.getElementById("unit-price");51 52     for (var i = 0; i < aInput.length; i++) {53         if (i % 2 != 0) { //加号54             aInput[i].onclick = function () {55                 //当前加号所在行的数量56                 var aNum = getByClass( "num", this.parentNode );57                 var n = parseInt( aNum[0].innerHTML );58                 n++;59                 aNum[0].innerHTML = n;60                 //获取单价61                 var aUnit = getByClass( "unit", this.parentNode );62                 var unitPrice = parseInt(aUnit[0].innerHTML);63                 var subtotal = getSubTotal( unitPrice, n );64                 var aSubtotal = getByClass( "subtotal", this.parentNode );65                 aSubtotal[0].innerHTML = subtotal;66                 total++; //商品总数67                 oGoodsNum.innerHTML = total;68                 oTotalPrice.innerHTML = getSum();69                 oUnitPrice.innerHTML = compareUnit();70             }71         }else {72             aInput[i].onclick = function(){73                 var aNum = getByClass( "num", this.parentNode );74                 if ( parseInt( aNum[0].innerHTML ) != 0 ){75                     var n = parseInt( aNum[0].innerHTML );76                     n--;77                     aNum[0].innerHTML = n;78                     //获取单价79                     var aUnit = getByClass( "unit", this.parentNode );80                     var unitPrice = parseInt(aUnit[0].innerHTML);81                     var subtotal = getSubTotal( unitPrice, n );82                     var aSubtotal = getByClass( "subtotal", this.parentNode );83                     aSubtotal[0].innerHTML = subtotal;84                     total--; //商品总数85                     oGoodsNum.innerHTML = total;86                     oTotalPrice.innerHTML = getSum();87                     oUnitPrice.innerHTML = compareUnit();88                 }89             }90         }91     }92 }

耦合度太高,可维护性很差.

重构之后的购物车:

 1 window.onload = function () { 2     var Event = { 3         userList: {}, 4         subscribe: function (key, fn) { 5             if (!this.userList[key]) { 6                 this.userList[key] = []; 7             } 8             this.userList[key].push(fn); 9         },10         publish: function () {11             var key = Array.prototype.shift.apply(arguments),12                 fns = this.userList[key];13             if (!fns || fns.length === 0) {14                 return false;15             }16             for (var i = 0, len = fns.length; i < len; i++) {17                 fns[i].apply(this, arguments);18             }19         }20     };21     (function(){22         var aBtnMinus = document.querySelectorAll( "#box li>input:first-child"),23             aBtnPlus = document.querySelectorAll( "#box li>input:nth-of-type(2)"),24             curNum = 0, curUnitPrice = 0;25 26         for( var i = 0, len = aBtnMinus.length; i < len; i++ ){27             aBtnMinus[i].index = aBtnPlus[i].index = i;28             aBtnMinus[i].onclick = function(){29                 (this.parentNode.children[1].innerHTML > 0) && Event.publish( "total-goods-num-minus" );30                 --this.parentNode.children[1].innerHTML < 0 && (this.parentNode.children[1].innerHTML = 0);31                 curUnitPrice = this.parentNode.children[4].innerHTML;32                 Event.publish( "minus-num" + this.index, 33                     parseInt( curUnitPrice ),34                     parseInt( this.parentNode.children[1].innerHTML )35                 );36             };37             aBtnPlus[i].onclick = function(){38                 (this.parentNode.children[1].innerHTML >= 0) && Event.publish( "total-goods-num-plus" );39                 this.parentNode.children[1].innerHTML++;40                 curUnitPrice = this.parentNode.children[4].innerHTML;41                 Event.publish( "plus-num" + this.index, 42                     parseInt( curUnitPrice ),43                     parseInt( this.parentNode.children[1].innerHTML )44                 );45             }46         }47     })();48     (function(){49         var aSubtotal = document.querySelectorAll("#box .subtotal"),50             oGoodsNum = document.querySelector("#goods-num"),51             oTotalPrice = document.querySelector("#total-price");52             Event.subscribe( 'total-goods-num-plus', function(){53                 ++oGoodsNum.innerHTML;54             });55             Event.subscribe( 'total-goods-num-minus', function(){56                 --oGoodsNum.innerHTML;57             });58         for( let i = 0, len = aSubtotal.length; i < len; i++ ){59             Event.subscribe( 'minus-num' + i, function( unitPrice, num ){60                 aSubtotal[i].innerHTML = unitPrice * num;61             });62             Event.subscribe( 'plus-num' + i, function( unitPrice, num ){63                 aSubtotal[i].innerHTML = unitPrice * num;64             });65         }66     })();67     console.log( Event.userList );68 }
阅读全文
0 0
原创粉丝点击