觀察者模式是一個(gè)行為型設(shè)計(jì)模式

特點(diǎn)

1 解決的是耦" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運(yùn)營 > web前端之設(shè)計(jì)模式(二)

web前端之設(shè)計(jì)模式(二)

時(shí)間:2023-09-04 02:54:01 | 來源:網(wǎng)站運(yùn)營

時(shí)間:2023-09-04 02:54:01 來源:網(wǎng)站運(yùn)營

web前端之設(shè)計(jì)模式(二):

一、設(shè)計(jì)模式

1.1 觀察者模式

定義:觀察者模式,又叫發(fā)布訂閱者模式,又叫消息系統(tǒng),又叫消息機(jī)制,又叫自定義事件,解決主體與觀察者之間的耦合問題

觀察者模式是一個(gè)行為型設(shè)計(jì)模式

特點(diǎn)

1 解決的是耦合問題(類與類之間,對(duì)象之間,類與對(duì)象之間,模塊之間)

2 對(duì)于任何一個(gè)觀察者來說,其它觀察者的改變不會(huì)影響自身

3 對(duì)于任何一個(gè)對(duì)象來說,既可以是觀察者,也可以是被觀察者

如:jQuery中的觀察者模式。$.CallBacks()方法執(zhí)行的結(jié)果得到一個(gè)觀察者對(duì)象,

觀察者對(duì)象有一個(gè)方法叫add,用來訂閱消息的。觀察對(duì)象有一個(gè)方法叫fire,用來發(fā)布消息

實(shí)現(xiàn)觀察者模式

觀者者對(duì)象必須具備兩個(gè)方法

on 用來注冊(cè)消息

第一個(gè)參數(shù)表示消息的名稱。

第二個(gè)參數(shù)表示回調(diào)函數(shù)

trigger 用來觸發(fā)消息

第一個(gè)參數(shù)表示消息的名稱。

從第二個(gè)參數(shù)開始表示傳遞數(shù)據(jù)

off 用來移除消息的方法,

參數(shù)同register

once 單次訂閱方法,

參數(shù)同register

通過閉包將接口返回,那么on和trigger對(duì)用戶來說就是可訪問的,閉包里面存儲(chǔ)消息隊(duì)列,對(duì)用戶來說就是不可見的,因此是安全。

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <script> // 觀察者模式又叫發(fā)布訂閱者模式,消息系統(tǒng),消息機(jī)制,自定義事件 var Observer = (function() { // 消息隊(duì)列 var _msg = {}; // 暴露接口 return { /*** * 訂閱消息 * @type 消息名稱 * fn 回調(diào)函數(shù) * 將消息回調(diào)函數(shù),存儲(chǔ)在消息隊(duì)列中 **/ on: function(type, fn) { // 判斷這種類型的消息是否存在 if (_msg[type]) { // 繼續(xù)存儲(chǔ) _msg[type].push(fn) } else { // 初始化一個(gè)消息管道 _msg[type] = [fn] } // console.log(_msg); }, /*** * 發(fā)布消息 * @type 消息類型 * 從第二個(gè)參數(shù)開始,表示執(zhí)行消息回調(diào)函數(shù)的時(shí)候,傳遞的參數(shù) * 遍歷該類型的消息回調(diào)函數(shù),并逐一執(zhí)行 **/ trigger: function(type) { // 該類型的消息是否存在 if (_msg[type]) { // 獲取傳遞的參數(shù) var args = Array.prototype.slice.call(arguments, 1); // console.log(args); // 遍歷消息管道,逐一執(zhí)行每一個(gè)方法 for(var i = 0; i < _msg[type].length; i++) { // 執(zhí)行每一個(gè)函數(shù), // args是一個(gè)數(shù)組,要逐一傳遞,因此要借助apply _msg[type][i].apply(null, args) // _msg[type][i](args) } } }, /*** * 注銷消息 * @type 消息名稱 * fn 回調(diào)函數(shù) 注意:匿名函數(shù)無法注銷 * 從消息隊(duì)列中,移除該回調(diào)函數(shù) **/ off: function(type, fn) { // 沒有傳遞參數(shù),情況消息隊(duì)列 // 傳遞了type,情況該類型的消息管道 // 傳遞了type和fn,從該類型的消息管道中,找到fn,并將其移除? // 沒有傳遞參數(shù),情況消息隊(duì)列 if (type === undefined) { _msg = {}; return; } // 是否有fn if (fn) { // 傳遞了type和fn,從該類型的消息管道中,找到fn,并將其移除 for (var i = _msg[type].length - 1; i >= 0; i--) { // 尋找fn if (_msg[type][i] === fn) { // 移除fn, 從后向前遍歷時(shí)候,從數(shù)組中刪除成員不會(huì)影響遍歷 _msg[type].splice(i, 1) // 刪除了,不需要繼續(xù)遍歷了。 return; } } } else { // 傳遞了type,情況該類型的消息管道 _msg[type] = []; } }, /*** * 單次訂閱的 * @type 消息名稱 * fn 回調(diào)函數(shù) * 注冊(cè)后將其移除 **/ once: function(type, fn) { // this.on(type, fn) // this.off(type, fn) // 緩存this var me = this; // 包裝函數(shù) function callback() { // 注銷回調(diào)函數(shù), 防止無限循環(huán)。 me.off(type, callback) // 執(zhí)行回調(diào)函數(shù),并傳遞參數(shù) // apply第二個(gè)參數(shù)可以是數(shù)組,也可以是類數(shù)組對(duì)象。 fn.apply(null, arguments); // console.log('執(zhí)行了') } // 訂閱 this.on(type, callback) } } })()?? // 觀察者模式問題:一定是先訂閱,再發(fā)布。 Observer.trigger('test', 100, 200)? // 單次訂閱 Observer.once('test', function() { console.log('run test', arguments); Observer.trigger('test', 'hello', 'ickt') })? // Observer.trigger('test', 100, 200) // Observer.trigger('test', true, false) // Observer.trigger('test', 'hello', 'ickt')?? // function demo() { // // console.log('helle ickt', this) // console.log('helle ickt') // } // // 訂閱消息 // Observer.on('ickt', function(num1, num2, bool, msg) { // // console.log(arguments) // console.log(num1, num2, bool, msg); // }) // Observer.on('ickt', demo) // Observer.on('demo', function() { // console.log(arguments) // }) // // 清空 // // Observer.off(); // // Observer.off('ickt'); // // 沒辦法注銷匿名函數(shù) // // Observer.off('ickt', function() { // // // console.log('helle ickt', this) // // console.log('helle ickt') // // }); // // Observer.off('ickt', demo)? // // 發(fā)布消息 // Observer.trigger('ickt', 100, 200, true, 'hello') // Observer.trigger('ickt', 100, 200, true, 'hello') // Observer.trigger('test', 100, 200) // Observer.trigger('demo', 100, 200)? </script></body></html>


1.2 組合模式

又叫部分-整體模式,將對(duì)象組裝成一個(gè)樹形結(jié)構(gòu)來表達(dá)這個(gè)整體,不論是部分還是整體,在表現(xiàn)上具有一致性。是結(jié)構(gòu)型設(shè)計(jì)模式。其特點(diǎn)

是一個(gè)拆分合并過程。為我們提供清晰的組成結(jié)構(gòu),

通過對(duì)基對(duì)象的屬性方法的繼承,使成員對(duì)象間的基本表現(xiàn),行為統(tǒng)一

成員對(duì)象的結(jié)構(gòu)簡單而又單一,這給我們帶來了更多的組合方式。

組合模式實(shí)現(xiàn)步驟

對(duì)整體拆分 -> 得到不同層級(jí)的個(gè)體。 對(duì)個(gè)體組裝 -> 組合得到不同的整體

所有個(gè)體都會(huì)繼承同一個(gè)基類

通常基類是只能被繼承,不會(huì)去實(shí)例化的的 (包含的是所有個(gè)體共有的屬性方法)

新聞模塊

整個(gè)新聞模塊是一個(gè)根節(jié)點(diǎn)

每一行是一個(gè)枝干節(jié)點(diǎn)

每一行有多條新聞,每一條新聞就是一個(gè)葉子節(jié)點(diǎn)(因此不能包含子節(jié)點(diǎn))

總結(jié)

是一個(gè)結(jié)構(gòu)型設(shè)計(jì)模式

本質(zhì)就是一個(gè)拆分合并的過程

整體與個(gè)體之間具有行為的一致性

對(duì)個(gè)體的不同的組裝,可以是整體差異化

組合模式使整體結(jié)構(gòu)很清晰

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> a:hover { color: #f90; } a { margin-right: 20px; } </style></head><body> <script src="./ickt.js"></script> <script> // 定義基類,讓所有類繼承 function Base() { // 當(dāng)前元素 this.element = null; // 存儲(chǔ)子類 this.children = []; } // 定義這些行文方法 Base.prototype.init = function() { // 基類不能初始化 throw new Error('基類不能初始化') } // 獲取當(dāng)前實(shí)例對(duì)應(yīng)的元素 Base.prototype.getElement = function() { return this.element; } // 添加子元素 Base.prototype.add = function(child) { // 存儲(chǔ)子對(duì)象 this.children.push(child); // 處理dom this.element.appendChild(child.getElement()); // 鏈?zhǔn)秸{(diào)用 return this; } // 容器類 function Container(id, parent) { // 構(gòu)造函數(shù)式繼承 Base.call(this); // 存儲(chǔ)數(shù)據(jù) this.id = id; this.parent = parent; // 初始化 this.init(); } // 可以使用類式繼承,也可以使用寄生式繼承 // Container.prototype = new Base(); _.inherit(Container, Base); // 重寫方法 // 初始化方法 Container.prototype.init = function() { // 創(chuàng)建元素 this.element = document.createElement('ul'); // 添加id this.element.id = this.id; // 添加類 this.element.className = 'container' } // 顯示容器 Container.prototype.show = function() { // 讓容器元素上樹 this.parent.appendChild(this.element); }? // 每一行的類 function Item(className) { // 構(gòu)造函數(shù)繼承 Base.call(this); // 存儲(chǔ)數(shù)據(jù) this.className = className || 'item'; // 初始化 this.init(); } // 繼承 _.inherit(Item, Base); // 重寫方法 Item.prototype.init = function() { // 創(chuàng)建元素 this.element = document.createElement('li'); // 設(shè)置屬性 this.element.className = this.className; }? // 沒有分類的新聞 function TitleNews(text, href) { // 構(gòu)造函數(shù)繼承 Base.call(this); // 存儲(chǔ)數(shù)據(jù) this.text = text; this.href = href; // 初始化 this.init(); } // 繼承 _.inherit(TitleNews, Base) // 重寫方法 // 初始化方法 TitleNews.prototype.init = function() { // 定義元素 this.element = document.createElement('a'); // 設(shè)置屬性 this.element.href = this.href; // 設(shè)置內(nèi)容 this.element.innerHTML = this.text; }? // 分類新聞 function TypeNews(text, href, type) { // 構(gòu)造函數(shù)繼承 Base.call(this); // 存儲(chǔ)數(shù)據(jù) this.text = text; this.href = href; this.type = type; // 初始化 this.init(); } // 繼承 _.inherit(TypeNews, Base) // 重寫方法 // 初始化方法 TypeNews.prototype.init = function() { // 創(chuàng)建元素 this.element = document.createElement('a'); var span = document.createElement('span'); var text = document.createTextNode(this.text); // 設(shè)置內(nèi)容 span.innerHTML = this.type + ' | '; // 設(shè)置屬性 this.element.href = this.href; // 組裝 this.element.appendChild(span) this.element.appendChild(text) }??? // 使用類 new Container('sport', document.body) .add( new Item() .add( new TitleNews('國安官宣與池忠國完成續(xù)約', 'www.baidu.com') ) .add( new TitleNews('足協(xié)明確外援出場規(guī)則', 'www.baidu.com') ) ) .add( new Item() .add( new TitleNews('180萬!詹皇球星卡拍賣創(chuàng)紀(jì)錄', 'www.baidu.com') ) ) .add( new Item() .add( new TypeNews('沈夢(mèng)辰時(shí)髦穿搭 趙麗穎夏日針織', '#demo', '時(shí)尚') ) ) .add( new Item() .add( new TypeNews('影院歸來票房超350萬:賠本攢人氣 但總要開始', '#demo', '科技') ) ) // 上樹 .show();? // 構(gòu)造一個(gè)新模塊 new Container('car', document.body) .add( new Item() .add( new TitleNews('小鵬汽車完成C+輪近5億美元融資', '#demo') ) ) .add( new Item() .add( new TypeNews('理想汽車計(jì)劃7月31日在納斯達(dá)克掛牌上市', '#demo', '汽車') ) ) .show(); </script></body></html>


1.3 策略模式

定義:將一組算法封裝起來,使其彼此之間可以相互替換,封裝的算法具有獨(dú)立性,不會(huì)隨著客戶端的變換而變化。。

行為型設(shè)計(jì)模式

特點(diǎn)

創(chuàng)建的一系列算法,每組算法的業(yè)務(wù)邏輯是相同的,但是處理的過程以及結(jié)果是不同的。

算法是獨(dú)立的,可以相互替換,解決了算法與使用者之間的耦合問題。

算法之間的獨(dú)立性使其方便進(jìn)行單元測試。

應(yīng)用:jQuery的動(dòng)畫算法就是一個(gè)策略模式,還有在處理商品促銷價(jià)格,以及表單校驗(yàn)的時(shí)候,也可以使用策略模式。

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <input type="text"> <script> // 封裝校驗(yàn)算法 var strage = (function() { // 校驗(yàn)算法 var methods = { // 校驗(yàn)數(shù)字 number: function(value) { // 判斷數(shù)組 if (!/^/d+$/.test(value)) { // 不是數(shù)字 return '不是數(shù)字' } }, // 校驗(yàn)內(nèi)容 en: function(value) { // 判斷數(shù)組 if (!/^[a-zA-Z]+$/.test(value)) { // 不是數(shù)字 return '不都是英文' } } } // 接口方法 return { // 校驗(yàn)方法 use: function(type, value) { // 找到校驗(yàn)策略,校驗(yàn)數(shù)據(jù) return methods[type] && methods[type](value) }, // 添加策略 add: function(type, fn) { // 存儲(chǔ)校驗(yàn)策略 methods[type] = fn; } } })()? // 輸入框輸入完成 var inp = document.getElementsByTagName('input')[0]; // 失去焦點(diǎn) inp.onblur = function(e) { // 校驗(yàn) // var result = strage.use('number', e.target.value) // var result = strage.use('en', e.target.value) // 添加校驗(yàn)方法 strage.add('nickname', function(value) { // 校驗(yàn) if (!/^/w{2,8}$/.test(value)) { // 提示錯(cuò)誤 return '用戶名是2到8為的字母數(shù)字下劃線'; } }) var result = strage.use('nickname', e.target.value) console.log(result); } </script></body></html>


1.4 命令模式

定義:將請(qǐng)求與實(shí)現(xiàn)解耦并封裝成獨(dú)立的對(duì)象,從而使不同的請(qǐng)求對(duì)客戶端實(shí)現(xiàn)的參數(shù)化。

行為型設(shè)計(jì)模式

特點(diǎn)

將執(zhí)行的命令封裝,解決命令的發(fā)起者與命令的執(zhí)行者之間的耦合

使用者不必了解每條命令的接口是如何實(shí)現(xiàn)的,命令是如何執(zhí)行的。

所有命令都被存儲(chǔ)在命令對(duì)象上。

命令的使用具有一致性,多數(shù)命令在一定程度上簡化了操作方法的實(shí)現(xiàn),

對(duì)命令的封裝,使得每次執(zhí)行時(shí)都要調(diào)用一次命令對(duì)象,增加了系統(tǒng)的復(fù)雜度

canvas 繪圖

繪制圓的過程中遇到哪些問題?

1 源生的API有時(shí)候不好用

繪制一個(gè)圓寫了5行代碼

繪制一個(gè)圓,只需要圓心坐標(biāo),半徑,顏色就夠了,其他的都多余

2 如果將ctx變量放在全局環(huán)境中,有風(fēng)險(xiǎn),可能會(huì)被人更改

3 如果將ctx變量保存在閉包中,外界就無法訪問了

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body style="text-align: center;"> <canvas width="1000" height="600" style="border: 1px solid pink"></canvas> <script> // // 獲取canvas // var canvas = document.getElementsByTagName('canvas')[0]; // // 設(shè)置樣式 // canvas.style.border = '1px solid pink'; // // 繪制圓 // var ctx = canvas.getContext('2d'); // // 繪制元素 // ctx.beginPath(); // // 繪制圓 // ctx.arc(200, 200, 100, 0, Math.PI * 2); // ctx.closePath(); // // 設(shè)置顏色 // ctx.strokeStyle = 'green'; // ctx.stroke();? // 分裝一個(gè)指令對(duì)象 var Command = (function() { // 獲取canvas var canvas = document.getElementsByTagName('canvas')[0]; // 繪制圓 var ctx = canvas.getContext('2d'); // 封裝指令 var _C = { // 描邊圓 strokeCircle: function(x, y, r, color) { ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.closePath(); // 設(shè)置顏色并描邊 ctx.strokeStyle = color; ctx.stroke(); }, // 填充元素 fillCircle: function(x, y, r, color) { ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.closePath(); // 設(shè)置顏色并描邊 ctx.fillStyle = color; ctx.fill(); }, // 繪制矩形 fillCenterRect: function(x, y, width, height, color) { // 傳遞了顏色,設(shè)置顏色 if (color) { ctx.fillStyle = color; } // 繪制 ctx.fillRect(x - width / 2, y - height / 2, width, height) } } // 暴露接口 return { // 執(zhí)行方法 exec: function(type) { // 獲取第二個(gè)參數(shù)開始,傳遞的參數(shù) var args = Array.prototype.slice.call(arguments, 1); // 執(zhí)行指令 _C[type] && _C[type].apply(null, args); // 鏈?zhǔn)秸{(diào)用 return this; } } })()? // 繪制圓 Command.exec('fillCircle', 100, 100, 50, 'green') Command.exec('strokeCircle', 300, 300, 50, 'pink') // 還可以鏈?zhǔn)秸{(diào)用 .exec('fillCircle', 300, 100, 50, 'green') .exec('fillCenterRect', 400, 200, 100, 100, 'orange') </script></body></html>

關(guān)鍵詞:模式,設(shè)計(jì)

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉