摘要:發布者訂閱者模式,是一種很常見的模式,比如一買賣房子生活中的買房,賣房,中介就構成了一個發布訂閱者模式,買房的人,一般需要的是房源,價格,使用面積等信息,他充當了訂閱者的角色中介拿到賣主的房源信息,根據手頭上掌握的客戶聯系信息買房的人的手機
發布者訂閱者模式,是一種很常見的模式,比如:
一、買賣房子
生活中的買房,賣房,中介就構成了一個發布訂閱者模式,買房的人,一般需要的是房源,價格,使用面積等信息,他充當了訂閱者的角色
中介拿到賣主的房源信息,根據手頭上掌握的客戶聯系信息(買房的人的手機號),通知買房的人,他充當了發布者的角色
賣主想賣掉自己的房子,就需要告訴中介,把信息交給中介發布
二,網站訂閱信息的用戶
訂閱者角色:需要訂閱某類信息的網民,如某個網站的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 2 3 4 5Title 6 7 8 91067 6811
57- 12 13 0 14 15 單價: 16 15元; 17 小計: 18 0元 19
20- 21 22 0 23 24 單價: 25 10元; 26 小計: 27 0元 28
29- 30 31 0 32 33 單價: 34 5元; 35 小計: 36 0元 37
38- 39 40 0 41 42 單價: 43 2元; 44 小計: 45 0元 46
47- 48 49 0 50 51 單價: 52 1元; 53 小計: 54 0元 55
5658 商品一共 59 0 60 件; 61 一共花費 62 0 63 元; 64 其中最貴的商品單價是0元 6566
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 }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85217.html
摘要:什么是路由通俗點說,就是不同的顯示不同的內容什么是單頁應用單頁,英文縮寫為,就是把各種功能做在一個頁面內那所謂的單頁路由應用就是在一個頁面內,通過切換地址欄的來實現切換內容的變化如何知道切換了呢當后面的錨文本發生變化時,會觸發事件。 什么是路由? 通俗點說,就是不同的URL顯示不同的內容 什么是單頁應用? 單頁,英文縮寫為SPA( Single Page Application),就是...
摘要:,開始我們的第一篇單一職責。通過解耦可以讓每個職責工更加有彈性地變化。關于本文本文轉自大叔的深入理解系列。深入理解系列文章,包括了原創,翻譯,轉載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現將其重新整理發布。 前言 Bob大叔提出并發揚了S.O.L.I.D五大原則,用來更好地進行面向對象編程,五大原則分別是: The Single Responsibility Princi...
摘要:好,師傅我們要學習帝吧人民,進能打,退能刷淘寶。恩,大致過程就是這樣,我們使用中介者模式想一想。首先,數據需要放在中介者模式內,用戶的一切操作,都會傳遞給中介者模式,由他來選擇是哪一個部分發生改變。 俗話說,一個模式三個坑。 中介者模式應該算最坑的一個模式,坑不在于他的原理。而在于他的名字和其他模式的使用,真尼瑪像。首先,中介者 好像是一切模式里面都有的一個東西,比如,享元模式中-元對...
摘要:設計模式的定義在面向對象軟件設計過程中針對特定問題的簡潔而優雅的解決方案。從前由于使用的局限性,和做的應用相對簡單,不被重視,就更談不上設計模式的問題。 ‘從大處著眼,從小處著手’,以前對這句話一知半解,自從踏出校門走入社會,開始工作以來,有了越來越深的理解,偶有發現這句話用在程序開發中也有用,所以,近段時間開始嘗試著分析jQuery源碼,分析angularjs源碼,學習設計模式。 設...
摘要:毫無疑問,設計模式于己于他人于系統都是多贏的設計模式使代碼編寫真正工程化設計模小書前端掘金這是一本關于的小書。 JavaScript 常見設計模式解析 - 掘金設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無疑問,設計模式于己于他人于系統都是多贏的;設計...
閱讀 2643·2021-11-11 16:55
閱讀 680·2021-09-04 16:40
閱讀 3078·2019-08-30 15:54
閱讀 2615·2019-08-30 15:54
閱讀 2403·2019-08-30 15:46
閱讀 404·2019-08-30 15:43
閱讀 3227·2019-08-30 11:11
閱讀 2983·2019-08-28 18:17