我們大家一聽到設計模式就感覺設計模式是一個高端的東西,到底什麼是設計模式呢?其實設計模式也就是我們的前輩在寫代碼的時候遇到的問題,提出的解決方案,為了方便人與人之間的交流,取了個名字,叫做設計模式。 創建型設計模式 本文今天主要寫一部分創建型設計模式,創建型設計模式呢就是我門創建對象的時候的一種模式 ...
我們大家一聽到設計模式就感覺設計模式是一個高端的東西,到底什麼是設計模式呢?其實設計模式也就是我們的前輩在寫代碼的時候遇到的問題,提出的解決方案,為了方便人與人之間的交流,取了個名字,叫做設計模式。
創建型設計模式
本文今天主要寫一部分創建型設計模式,創建型設計模式呢就是我門創建對象的時候的一種模式。廢話不多說了,直接上代碼和解釋吧。
單例模式
目的:單例模式的目的是為瞭解決全局命名空間污染,衝突。
1 function g(id) { 2 return document.getElementById(id); 3 } 4 5 function css(id,key,value) { 6 g(id).style[key] = value; 7 } 8 9 function html(id,value) { 10 g(id).innerHTML = value; 11 } 12 13 function on(id,type,fn) { 14 g(id)['on'+type] = fn; 15 }
上面的代碼在頁面中添加了許多的變數,日後其他的人要為頁面添加新的需求時,增加代碼或者是重寫了代碼,比如這個on方法,那麼就會和其他人的代碼衝突,所以可以用單例模式來書寫一下代碼。
代碼樣式如下
1 //工程師 z 2 var xiaoz = { 3 g : function (id) { 4 return document.getElementById(id); 5 }, 6 css : function (id,key,value) { 7 g(id).style[key] = value; 8 } 9 }; 10 //工程師 y 11 var xiaoy = { 12 css : function () { 13 //一堆代碼 14 } 15 };
這樣幾個人之間的代碼就不會相互影響了,上面的代碼調用的方式如下。
1 xiaoz.g('box');
在單例模式中還有另外一種,關於靜態變數在es6才提出來的const,靜態變數是一旦確定就無法修改的量,但是現在es6的相容性還不是太好,在單例模式中同樣可以模擬這種可以定義但是無法改變的變數。
1 var wulv5 = (function(){ 2 var bian = { 3 a : 1, 4 b : 2, 5 fn : function(){ 6 console.log('這裡是fn') 7 } 8 }; 9 return { 10 getdata:function(val){ 11 return bian[val]; 12 } 13 } 14 })(); 15 //裡面的變數只能獲取 不能修改
簡單工廠模式
簡單工廠模式不是解決命名空間問題的,是為瞭解決創建對象的。
看下麵的代碼例子
//牛排 function Steak(){ this.price = 30; this.time = 20; } //炒飯 function FriedRice(){ this.price = 10; this.time = 5; } //麵條 function Noodles(){ this.price = 15; this.time = 10; } var a = new Steak(); var b = new FriedRice(); var c = new Noodles(); //歸類 開了個飯店a賣牛排 又開了個飯店b 賣炒飯 //開一家就可以了
上面的代碼就相當於我們開飯店,我們開了一家賣牛排的店,又開了一家賣炒飯的店,然後又開了一家賣麵條的店,雖然我們比較有錢,但是其實開一家店賣這幾樣東西就可以了
所以我們歸類,看下麵的代碼就是簡單工廠模式
1 function Shop(name){ 2 var o = null; 3 switch(name){ 4 case 'Steak' : 5 o = new Steak(); 6 break; 7 case 'FriedRice' : 8 o = new FriedRice(); 9 break; 10 case 'Noodles' : 11 o = new Noodles(); 12 break; 13 } 14 return o; 15 } 16 17 new Shop('Noodles'); 18 //好處 比如手機裡面有很多軟體 軟體歸類 好找 不用記什麼是什麼了 19 20 //缺點 這個拓展有點不好
至於說缺點拓展性不好的理由呢就是,比如我們又要開一家烤鴨店的話,我們不僅要定義一個烤鴨的構造函數,而且還要在工廠中增加一個判斷,這個我就不寫了,下麵看看工廠模式就解決了這個問題
工廠模式
1 function Shop(name) { 2 console.log(this); 3 return new this[name](); 4 } 5 6 7 Shop.prototype = { 8 Steak : function () { 9 this.price = 30; 10 this.time = 20; 11 }, 12 FriedRice : function () { 13 this.price = 30; 14 this.time = 20; 15 }, 16 Noodles : function () { 17 this.price = 30; 18 this.time = 20; 19 } 20 }; 21 22 var obj = new Shop('FriedRice'); 23 24 console.log(obj);
上面的如果在拓展的話直接在原型上拓展就可以了,非常方便。也非常好用。
原型模式
原型模式是為瞭解決....
好了先不說解決什麼,我們來幾個需求
比如說我們需要寫一個輪播圖,我們就開始寫了,樣式就不寫了哈。
<div>
<ul>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
</ul>
</div>
1 var oUl = document.getElementsByTagName('ul')[0]; 2 aLi = document.getElementsByTagName('li'); 3 4 var index = 0, 5 len = aLi.length; 6 7 function Fn() { 8 oUl.style.left = 600*index; 9 index %= len; 10 index++; 11 } 12 13 setInterval(Fn,1000);
應該是可以實現的吧,沒有實驗,如果有錯誤指正一下。有問題又來了,如果又有一個新的輪播圖需要在輪播圖上面添加上兩個前進後退按鈕,那麼你會怎麼做,你可能會想反正代碼也不多我直接拿過來複制,在添加幾行代碼不就完了嗎,是這樣的沒錯,可是你想想如果有好多的輪播特效,你是不是每一種特效都需要複製一下上面的代碼呢,他們都是重覆的,所以我們可以用原型模式把上面的代碼來繼承下來。
1 var oUl = document.getElementsByTagName('ul')[0], 2 aLi = document.getElementsByTagName('li'), 3 div = document.querySelector('div'); 4 5 var index = 0; 6 7 //基本滾動 8 function Banner(div){ 9 this.dom = div; 10 this.init(); 11 } 12 //原型 13 Banner.prototype.init = function(){ 14 var oUl = this.dom.getElementsByTagName('ul')[0]; 15 var aLi = oUl.getElementsByTagName('li'), 16 len = aLi.length; 17 setInterval(function () { 18 oUl.style.left = 600*index; 19 index %= len; 20 index++; 21 },1000) 22 }; 23 24 // 那麼這個時候只需要繼承過來 然後再這基礎之上進行擴展 簡單點就是原型繼承 25 function F() {} 26 F.prototype = Banner.prototype; 27 28 function Banner2(dom) { 29 Banner.call(this,dom); 30 this.goudan(); 31 } 32 Banner2.prototype = new F(); 33 Banner2.prototype.Slide = function () { 34 console.log('滾動'); 35 }; 36 37 new Banner2(div);
代碼可能不是那麼嚴謹,這裡你知道大概的目的是什麼就可以了,你還可以在他的原型上面拓展出來好多其他特效,當然這種模式不僅僅應用於輪播圖特效,是為了代碼的復用問題。
建造者模式
比如我們在工作需求中,需求經常發生變動,有時候一些變化可能會引起許多代碼的修改,這時我們的解決方案出來了,可以把一個對象分步驟建造出來,實現的功能分步驟單例出來。看一下下麵的小例子
發佈簡歷
1 //簡歷 : 人,姓名,職位 2 var Human = function(param){ 3 //技能 4 this.name = param || '保密'; 5 }; 6 Human.prototype.getname = function(){ 7 return this.name; 8 }; 9 var Work = function(work){ 10 switch(work){ 11 case 'code': 12 this.work = '工程師'; 13 this.workDescript = '每天沉迷於編程'; 14 break; 15 case 'UI': 16 this.work = '設計師'; 17 this.workDescript = '設計是一種態度'; 18 break; 19 case 'teach': 20 this.work = '教師'; 21 this.workDescript = '分享也是一種態度'; 22 break; 23 default: 24 this.work = work; 25 this.workDescript = '對不起我們還不清楚你的職位描述'; 26 } 27 }; 28 29 //最終創建的對象 30 var Person = function(skill,work){ 31 var _Person = new Human(skill); 32 _Person.work = new Work(work); 33 return _Person; 34 }; 35 //這樣就可以 36 Person('xiaoz',teach);
前面幾種工廠模式,他們都有一個共同的特點,就是創建的結果都是一個完整的個體,對創建的過程不得而知,我們只知道得到的創建結果,而在建造者模式當中,我們關心的是對象的創建過程,因為我們通常將創建對象的類模塊化,這樣使被創建的類的每一個模塊都可以得到靈活的額運用與高質量的復用,在這個過程中我們又組合成一個完整的個體。
這種方式對於整體對象又變得複雜了一些,所以如果對象很小,我們最好還是創建整體對象。
如果你閱讀了本文章有了一些收穫,我會感到非常開心,由於能力有限,文章有的部分解釋的不到位,希望在以後的日子里能慢慢提高自己能力,如果不足之處,還望指正。
在接下來的時間,我還會把其他的一些常用的設計模式分享給大家,希望可以支持一下。