常用的javascript設(shè)計(jì)模式
閱讀目錄
- 什么是設(shè)計(jì)模式
- 單體模式:
- 工廠模式:
- 單例模式
- 觀察者模式(發(fā)布訂閱模式)
- 策略模式
- 模板模式
- 代理模式
- 外觀模式
設(shè)計(jì)模式太多了,貌似有23種,其實(shí)我們?cè)谄綍r(shí)的工作中沒(méi)有必要特意去用什么樣的設(shè)計(jì)模式,或者你在不經(jīng)意間就已經(jīng)用了設(shè)計(jì)模式當(dāng)中的一種。本文旨在總結(jié)平時(shí)相對(duì)來(lái)說(shuō)用的比較多的設(shè)計(jì)模式。
什么是設(shè)計(jì)模式
百度百科:
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無(wú)疑問(wèn),設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的;設(shè)計(jì)模式使代碼編制真正工程化;設(shè)計(jì)模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。
實(shí)際情況:
設(shè)計(jì)模式絕對(duì)不是紙上談兵的知識(shí),光看書(shū)就以為自己懂了,那只是井底之蛙之見(jiàn),設(shè)計(jì)模式絕對(duì)是從實(shí)踐中來(lái)到實(shí)踐中去的!如果編碼經(jīng)驗(yàn)很少,也不太可能能理解好設(shè)計(jì)模式,但凡軟件設(shè)計(jì)能力強(qiáng)的人編碼功底都是相當(dāng)扎實(shí)的。
如果沒(méi)有能深刻理解面向?qū)ο?,也不太可能理解好設(shè)計(jì)模式,剛剛畢業(yè)或者才工作一兩年就說(shuō)自己面向?qū)ο竽芰?qiáng)的人,基本上就是夸夸其談的人。
很明顯,我就是屬于那種夸夸其談的人,哈哈,不過(guò)希望對(duì)本文的總結(jié),讓自己更加了解這些設(shè)計(jì)模式,理解的更加透徹。
單體模式:
概念:
單體是一個(gè)用來(lái)劃分命名空間并將一批相關(guān)的屬性和方法組織在一起的對(duì)象,如果他可以被實(shí)例化,那么他只能被實(shí)例化一次。
特點(diǎn):
可以來(lái)劃分命名空間,從而清除全局變量所帶來(lái)的危險(xiǎn)。
利用分支技術(shù)來(lái)來(lái)封裝瀏覽器之間的差異。
可以把代碼組織的更為一體,便于閱讀和維護(hù)。
代碼實(shí)現(xiàn):
/*Basic Singleton*/
var Singleton = {
attribute:true,
method1:function(){},
method2:function(){}
};
應(yīng)用場(chǎng)景:
單體模式在我們平時(shí)的應(yīng)用中用的比較多的,相當(dāng)于把我們的代碼封裝在一個(gè)起來(lái),只是暴露一個(gè)入口,從而避免全部變量的污染。
工廠模式:
概念:
工廠模式的定義:提供創(chuàng)建對(duì)象的接口,意思就是根據(jù)領(lǐng)導(dǎo)(調(diào)用者)的指示(參數(shù)),生產(chǎn)相應(yīng)的產(chǎn)品(對(duì)象)。
創(chuàng)建一個(gè)對(duì)象常常需要復(fù)雜的過(guò)程,所以不適合在一個(gè)復(fù)雜的對(duì)象中。
創(chuàng)建對(duì)象可能會(huì)導(dǎo)致大量的重復(fù)代碼,也可能提供不了足夠級(jí)別的抽象。
工廠就是把成員對(duì)象的創(chuàng)建工作轉(zhuǎn)交給一個(gè)外部對(duì)象,好處在于消除對(duì)象之間的耦合(也就是相互影響)
分類:
簡(jiǎn)單工廠模式:使用一個(gè)類,通常為單體,來(lái)生成實(shí)例。
復(fù)雜工廠模式定義是:將其成員對(duì)象的實(shí)列化推到子類中,子類可以重寫(xiě)父類接口方法以便創(chuàng)建的時(shí)候指定自己的對(duì)象類型。
父類只對(duì)創(chuàng)建過(guò)程中的一般性問(wèn)題進(jìn)行處理,這些處理會(huì)被子類繼承,子類之間是相互獨(dú)立的,具體的業(yè)務(wù)邏輯會(huì)放在子類中進(jìn)行編寫(xiě)。
代碼實(shí)現(xiàn):
簡(jiǎn)單工廠模式:
var XMLHttpFactory =function(){}; //這是一個(gè)簡(jiǎn)單工廠模式
XMLHttpFactory.createXMLHttp =function(){
var XMLHttp = null;
if (window.XMLHttpRequest){
XMLHttp = new XMLHttpRequest()
}else if (window.ActiveXObject){
XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
}
return XMLHttp;
}
//XMLHttpFactory.createXMLHttp()這個(gè)方法根據(jù)當(dāng)前環(huán)境的具體情況返回一個(gè)XHR對(duì)象。
var AjaxHander =function(){
var XMLHttp = XMLHttpFactory.createXMLHttp();
...
}
復(fù)雜工廠模式:流程==》 先設(shè)計(jì)一個(gè)抽象類,這個(gè)類不能被實(shí)例化,只能用來(lái)派生子類,最后通過(guò)對(duì)子類的擴(kuò)展實(shí)現(xiàn)工廠方法
var XMLHttpFactory =function(){}; //這是一個(gè)抽象工廠模式
XMLHttpFactory.prototype = {
//如果真的要調(diào)用這個(gè)方法會(huì)拋出一個(gè)錯(cuò)誤,它不能被實(shí)例化,只能用來(lái)派生子類
createFactory:function(){
throw new Error('This is an abstract class');
}
}
var XHRHandler =function(){}; //定義一個(gè)子類
// 子類繼承父類原型方法
extend( XHRHandler , XMLHttpFactory );
XHRHandler.prototype =new XMLHttpFactory(); //把超類原型引用傳遞給子類,實(shí)現(xiàn)繼承
XHRHandler.prototype.constructor = XHRHandler; //重置子類原型的構(gòu)造器為子類自身
//重新定義createFactory 方法
XHRHandler.prototype.createFactory =function(){
var XMLHttp =null;
if (window.XMLHttpRequest){
XMLHttp =new XMLHttpRequest();
}else if (window.ActiveXObject){
XMLHttp =new ActiveXObject("Microsoft.XMLHTTP")
}
return XMLHttp;
}
應(yīng)用場(chǎng)景:
以下幾種情景下工廠模式特別有用:
(1)對(duì)象的構(gòu)建十分復(fù)雜
(2)需要依賴具體環(huán)境創(chuàng)建不同實(shí)例
(3)處理大量具有相同屬性的小對(duì)象
優(yōu)點(diǎn):
可以實(shí)現(xiàn)一些相同的方法,這些相同的方法我們可以放在父類中編寫(xiě)代碼,那么需要實(shí)現(xiàn)具體的業(yè)務(wù)邏輯,那么可以放在子類中重寫(xiě)該父類的方法,去實(shí)現(xiàn)自己的業(yè)務(wù)邏輯;
也就是說(shuō)有兩點(diǎn):
1、弱化對(duì)象間的耦合,防止代碼的重復(fù)。在一個(gè)方法中進(jìn)行類的實(shí)例化,可以消除重復(fù)性的代碼。
2、重復(fù)性的代碼可以放在父類去編寫(xiě),子類繼承于父類的所有成員屬性和方法,子類只專注于實(shí)現(xiàn)自己的業(yè)務(wù)邏輯。
缺點(diǎn):
當(dāng)工廠增加到一定程度的時(shí)候,提升了代碼的復(fù)雜度,可讀性下降。而且沒(méi)有解決對(duì)象的識(shí)別問(wèn)題,即怎么知道一個(gè)對(duì)象的類型。
單例模式
概念:
單例模式定義了一個(gè)對(duì)象的創(chuàng)建過(guò)程,此對(duì)象只有一個(gè)單獨(dú)的實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。也可以說(shuō)單例就是保證一個(gè)類只有一個(gè)實(shí)例,實(shí)現(xiàn)的方法一般是先判斷實(shí)例存在與否,如果存在直接返回,如果不存在就創(chuàng)建了再返回,這就確保了一個(gè)類只有一個(gè)實(shí)例對(duì)象。
代碼實(shí)現(xiàn):
單例的實(shí)現(xiàn)有很多種,下面只介紹其中的一種,使用閉包方式來(lái)實(shí)現(xiàn)單例,代碼如下:
var single = (function(){
var unique;
function getInstance(){
// 如果該實(shí)例存在,則直接返回,否則就對(duì)其實(shí)例化
if( unique === undefined ){
unique = new Construct();
}
return unique;
}
function Construct(){
// ... 生成單例的構(gòu)造函數(shù)的代碼
}
return {
getInstance : getInstance
}
})();
上面的代碼中,unique便是返回對(duì)象的引用,而 getInstance便是靜態(tài)方法獲得實(shí)例。Construct 便是創(chuàng)建實(shí)例的構(gòu)造函數(shù)。
可以通過(guò) single.getInstance() 來(lái)獲取到單例,并且每次調(diào)用均獲取到同一個(gè)單例。這就是 單例模式 所實(shí)現(xiàn)的效果。
使用場(chǎng)景:
單例模式是一種常用的模式,有一些對(duì)象我們往往只需要一個(gè),比如全局緩存、瀏覽器的window對(duì)象。在js開(kāi)發(fā)中,單例模式的用途同樣非常廣泛。試想一下,當(dāng)我們
單擊登錄按鈕的時(shí)候,頁(yè)面中會(huì)出現(xiàn)一個(gè)登錄框,而這個(gè)浮窗是唯一的,無(wú)論單擊多少次登錄按鈕,這個(gè)浮窗只會(huì)被創(chuàng)建一次。因此這個(gè)登錄浮窗就適合用單例模式。
總結(jié)一下它的使用場(chǎng)景:
1、可以用它來(lái)劃分命名空間
2、借助單例模式,可以把代碼組織的更為一致,方便閱讀與維護(hù)
觀察者模式(發(fā)布訂閱模式)
概念:
定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,以便當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并自動(dòng)刷新,也被稱為是發(fā)布訂閱模式。
它需要一種高級(jí)的抽象策略,以便訂閱者能夠彼此獨(dú)立地發(fā)生改變,而發(fā)行方能夠接受任何有消費(fèi)意向的訂閱者。
應(yīng)用場(chǎng)景:
這個(gè)模式要先說(shuō)應(yīng)用場(chǎng)景,比較好理解。
打一個(gè)離我們比較近的一個(gè)場(chǎng)景,博客園里面有一個(gè)訂閱的按鈕(貌似有bug),比如小A,小B,小C都訂閱了我的博客,當(dāng)我的博客一有更新時(shí),就會(huì)統(tǒng)一發(fā)布郵件給他們這三個(gè)人,就會(huì)通知這些訂閱者
發(fā)布訂閱模式的流程如下:
1. 確定誰(shuí)是發(fā)布者(比如我的博客)。
2. 然后給發(fā)布者添加一個(gè)緩存列表,用于存放回調(diào)函數(shù)來(lái)通知訂閱者。
3. 發(fā)布消息,發(fā)布者需要遍歷這個(gè)緩存列表,依次觸發(fā)里面存放的訂閱者回調(diào)函數(shù)。
4. 退訂(比如不想再接收到這些訂閱的信息了,就可以取消掉)
代碼如下:
var pubsub = {}; // 定義發(fā)布者
(function (q) {
var list = [], //回調(diào)函數(shù)存放的數(shù)組,也就是記錄有多少人訂閱了我們東西
subUid = -1;
// 發(fā)布消息,遍歷訂閱者
q.publish = function (type, content) {
// type 為文章類型,content為文章內(nèi)容
// 如果沒(méi)有人訂閱,直接返回
if (!list[type]) {
return false;
}
setTimeout(function () {
var subscribers = list[type],
len = subscribers ? subscribers.length : 0;
while (len--) {
// 將內(nèi)容注入到訂閱者那里
subscribers[len].func(type, content);
}
}, 0);
return true;
};
//訂閱方法,由訂閱者來(lái)執(zhí)行
q.subscribe = function (type, func) {
// 如果之前沒(méi)有訂閱過(guò)
if (!list[type]) {
list[type] = [];
}
// token相當(dāng)于訂閱者的id,這樣的話如果退訂,我們就可以針對(duì)它來(lái)知道是誰(shuí)退訂了。
var token = (++subUid).toString();
// 每訂閱一個(gè),就把它存入到我們的數(shù)組中去
list[type].push({
token: token,
func: func
});
return token;
};
//退訂方法
q.unsubscribe = function (token) {
for (var m in list) {
if (list[m]) {
for (var i = 0, j = list[m].length; i < j; i++) {
if (list[m][i].token === token) {
list[m].splice(i, 1);
return token;
}
}
}
}
return false;
};
} (pubsub));
//將訂閱賦值給一個(gè)變量,以便退訂
var girlA = pubsub.subscribe('js類的文章', function (type, content) {
console.log('girlA訂閱的'+type + ": 內(nèi)容內(nèi)容為:" + content);
});
var girlB = pubsub.subscribe('js類的文章', function (type, content) {
console.log('girlB訂閱的'+type + ": 內(nèi)容內(nèi)容為:" + content);
});
var girlC = pubsub.subscribe('js類的文章', function (type, content) {
console.log('girlC訂閱的'+type + ": 內(nèi)容內(nèi)容為:" + content);
});
//發(fā)布通知
pubsub.publish('js類的文章', '關(guān)于js的內(nèi)容');
// 輸出:
// girlC訂閱的js類的文章: 內(nèi)容內(nèi)容為:關(guān)于js的內(nèi)容
// test3.html:78 girlB訂閱的js類的文章: 內(nèi)容內(nèi)容為:關(guān)于js的內(nèi)容
// test3.html:75 girlA訂閱的js類的文章: 內(nèi)容內(nèi)容為:關(guān)于js的內(nèi)容
//girlA退訂了關(guān)于js類的文章
setTimeout(function () {
pubsub.unsubscribe(girlA);
}, 0);
//再發(fā)布一次,驗(yàn)證一下是否還能夠輸出信息
pubsub.publish('js類的文章', "關(guān)于js的第二篇文章");
// 輸出:
// girlB訂閱的js類的文章: 內(nèi)容內(nèi)容為:關(guān)于js的第二篇文章
// girlC訂閱的js類的文章: 內(nèi)容內(nèi)容為:關(guān)于js的第二篇文章
代碼可以自己運(yùn)行一遍,這樣比較好理解
優(yōu)缺點(diǎn):
優(yōu)點(diǎn):當(dāng)我們需要維護(hù)相關(guān)對(duì)象的一致性的時(shí)候,使用觀察者模式,,就可以避免對(duì)象之間的緊密耦合。例如,一個(gè)對(duì)象可以通知另外一個(gè)對(duì)象,而不需要知道這個(gè)對(duì)象的信息。
缺點(diǎn):在發(fā)布/訂閱模式中,如果我們需要將發(fā)布者同訂閱者上解耦,將會(huì)在一些情況下,導(dǎo)致很難確保我們應(yīng)用中的特定部分按照我們預(yù)期的那樣正常工作。也就是說(shuō)它的優(yōu)點(diǎn)也可能是它的缺點(diǎn)
策略模式
概念:
策略模式指的是定義一些列的算法,把他們一個(gè)個(gè)封裝起來(lái),目的就是將算法的使用與算法的實(shí)現(xiàn)分離開(kāi)來(lái)。說(shuō)白了就是以前要很多判斷的寫(xiě)法,現(xiàn)在把判斷里面的內(nèi)容抽離開(kāi)來(lái),變成一個(gè)個(gè)小的個(gè)體。
代碼實(shí)現(xiàn):
代碼情景為超市促銷,vip為5折,老客戶3折,普通顧客沒(méi)折,計(jì)算最后需要支付的金額。
沒(méi)有使用策略模式的情況:
function Price(personType, price) {
//vip 5 折
if (personType == 'vip') {
return price * 0.5;
}
else if (personType == 'old'){ //老客戶 3 折
return price * 0.3;
} else {
return price; //其他都全價(jià)
}
}
不足之處:不好的地方,當(dāng)我有其他方面的折扣時(shí),又或者我活動(dòng)的折扣時(shí)經(jīng)常變化的,這樣就要不斷的修改if..else里面的條件了。而且也違背了設(shè)計(jì)模式的一個(gè)原則:對(duì)修改關(guān)閉,對(duì)擴(kuò)展開(kāi)放的原則;
使用策略模式之后:
// 對(duì)于vip客戶
function vipPrice() {
this.discount = 0.5;
}
vipPrice.prototype.getPrice = function(price) {
return price * this.discount;
}
// 對(duì)于老客戶
function oldPrice() {
this.discount = 0.3;
}
oldPrice.prototype.getPrice = function(price) {
return price * this.discount;
}
// 對(duì)于普通客戶
function Price() {
this.discount = 1;
}
Price.prototype.getPrice = function(price) {
return price ;
}
// 上下文,對(duì)于客戶端的使用
function Context() {
this.name = '';
this.strategy = null;
this.price = 0;
}
Context.prototype.set = function(name, strategy, price) {
this.name = name;
this.strategy = strategy;
this.price = price;
}
Context.prototype.getResult = function() {
console.log(this.name + ' 的結(jié)賬價(jià)為: ' + this.strategy.getPrice(this.price));
}
var context = new Context();
var vip = new vipPrice();
context.set ('vip客戶', vip, 200);
context.getResult(); // vip客戶 的結(jié)賬價(jià)為: 100
var old = new oldPrice();
context.set ('老客戶', old, 200);
context.getResult(); // 老客戶 的結(jié)賬價(jià)為: 60
var Price = new Price();
context.set ('普通客戶', Price, 200);
context.getResult(); // 普通客戶 的結(jié)賬價(jià)為: 200
通過(guò)策略模式,使得客戶的折扣與算法解藕,又使得修改跟擴(kuò)展能獨(dú)立的進(jìn)行,不影到客戶端或其他算法的使用;
使用場(chǎng)景:
策略模式最實(shí)用的場(chǎng)合就是某個(gè)“類”中包含有大量的條件性語(yǔ)句,比如if...else 或者 switch。每一個(gè)條件分支都會(huì)引起該“類”的特定行為以不同的方式作出改變。以其維
護(hù)一段龐大的條件性語(yǔ)句,不如將每一個(gè)行為劃分為多個(gè)獨(dú)立的對(duì)象。每一個(gè)對(duì)象被稱為一個(gè)策略。設(shè)置多個(gè)這種策略對(duì)象,可以改進(jìn)我們的代碼質(zhì)量,也更好的進(jìn)行單元測(cè)試。
模板模式
概念:
定義了一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
通俗的講,就是將一些公共方法封裝到父類,子類可以繼承這個(gè)父類,并且可以在子類中重寫(xiě)父類的方法,從而實(shí)現(xiàn)自己的業(yè)務(wù)邏輯。
代碼實(shí)現(xiàn):
比如前端面試,基本包括筆試,技術(shù)面試,領(lǐng)導(dǎo)面試,HR面試等,但是每個(gè)公司的筆試題,技術(shù)面可能不一樣,也可能一樣,一樣的就繼承父類的方法,不一樣的就重寫(xiě)父類的方法
var Interview = function(){};
// 筆試
Interview.prototype.writtenTest = function(){
console.log("這里是前端筆試題");
};
// 技術(shù)面試
Interview.prototype.technicalInterview = function(){
console.log("這里是技術(shù)面試");
};
// 領(lǐng)導(dǎo)面試
Interview.prototype.leader = function(){
console.log("領(lǐng)導(dǎo)面試");
};
// 領(lǐng)導(dǎo)面試
Interview.prototype.HR = function(){
console.log("HR面試");
};
// 等通知
Interview.prototype.waitNotice = function(){
console.log("等通知啊,不知道過(guò)了沒(méi)有哦");
};
// 代碼初始化
Interview.prototype.init = function(){
this.writtenTest();
this.technicalInterview();
this.leader();
this.HR();
this.waitNotice();
};
// 阿里巴巴的筆試和技術(shù)面不同,重寫(xiě)父類方法,其他繼承父類方法。
var AliInterview = function(){};
AliInterview.prototype = new Interview();
// 子類重寫(xiě)方法 實(shí)現(xiàn)自己的業(yè)務(wù)邏輯
AliInterview.prototype.writtenTest = function(){
console.log("阿里的技術(shù)題就是難啊");
}
AliInterview.prototype.technicalInterview = function(){
console.log("阿里的技術(shù)面就是叼啊");
}
var AliInterview = new AliInterview();
AliInterview.init();
// 阿里的技術(shù)題就是難啊
// 阿里的技術(shù)面就是叼啊
// 領(lǐng)導(dǎo)面試
// HR面試
// 等通知啊,不知道過(guò)了沒(méi)有哦
應(yīng)用場(chǎng)景:
模板模式主要應(yīng)用在一些代碼剛開(kāi)要一次性實(shí)現(xiàn)不變的部分。但是將來(lái)頁(yè)面有修改,需要更改業(yè)務(wù)邏輯的部分或者重新添加新業(yè)務(wù)的情況。主要是通過(guò)子類來(lái)改寫(xiě)父類的情況,其他不需要改變的部分繼承父類。
代理模式
概念:
代理模式的中文含義就是幫別人做事,javascript的解釋為:把對(duì)一個(gè)對(duì)象的訪問(wèn), 交給另一個(gè)代理對(duì)象來(lái)操作.
代碼實(shí)現(xiàn):
比如我們公司的補(bǔ)打卡是最后是要交給大boss來(lái)審批的,但是公司那么多人,每天都那么多補(bǔ)打卡,那大boss豈不是被這些瑣事累死。所以大boss下會(huì)有一個(gè)助理,來(lái)幫
忙做這個(gè)審批,最后再將每個(gè)月的補(bǔ)打卡統(tǒng)一交給大boss看看就行。
// 補(bǔ)打卡事件
var fillOut = function (lateDate) {
this.lateDate = lateDate;
};
// 這是bigBoss
var bigBoss = function (fillOut) {
this.state = function (isSuccess) {
console.log("忘記打卡的日期為:" + fillOut.lateDate + ", 補(bǔ)打卡狀態(tài):" + isSuccess);
}
};
// 助理代理大boss 完成補(bǔ)打卡審批
var proxyAssis = function (fillOut) {
this.state = function (isSuccess) {
(new bigBoss(fillOut)).state(isSuccess); // 替bigBoss審批
}
};
// 調(diào)用方法:
var proxyAssis = new proxyAssis(new fillOut("2016-9-11"));
proxyAssis.state("補(bǔ)打卡成功");
// 忘記打卡的日期為:2016-9-11, 補(bǔ)打卡狀態(tài):補(bǔ)打卡成功
應(yīng)用場(chǎng)景:
比如圖片的懶加載,我們就可以運(yùn)用這種技術(shù)。在圖片未加載完成之前,給個(gè)loading圖片,加載完成后再替換成實(shí)體路徑。
var myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return function(src){
imgNode.src = src;
}
})();
// 代理模式
var ProxyImage = (function(){
var img = new Image();
img.onload = function(){
myImage(this.src);
};
return function(src) {
// 占位圖片loading
myImage("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif");
img.src = src;
}
})();
// 調(diào)用方式
ProxyImage("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png"); // 真實(shí)要展示的圖片
當(dāng)然,這種懶加載方法不用代理模式也是可以實(shí)現(xiàn)的,只是用代理模式。我們可以讓 myImage 只做一件事,只負(fù)責(zé)將實(shí)際圖片加入到頁(yè)面中,而loading圖片交給ProxyImage去做。從而降低代碼的耦合度。因?yàn)楫?dāng)我不想用loading的時(shí)候,可以直接調(diào)用myImage 方法。也即是說(shuō)假如我門不需要代理對(duì)象的話,直接可以換成本體對(duì)象調(diào)用該方法即可。
外觀模式
概念:
外觀模式是很常見(jiàn)。其實(shí)它就是通過(guò)編寫(xiě)一個(gè)單獨(dú)的函數(shù),來(lái)簡(jiǎn)化對(duì)一個(gè)或多個(gè)更大型的,可能更為復(fù)雜的函數(shù)的訪問(wèn)。也就是說(shuō)可以視外觀模式為一種簡(jiǎn)化某些內(nèi)容的手段。
說(shuō)白了,外觀模式就是一個(gè)函數(shù),封裝了復(fù)雜的操作。
代碼實(shí)現(xiàn):
比如一個(gè)跨瀏覽器的ajax調(diào)用
function ajaxCall(type,url,callback,data){
// 根據(jù)當(dāng)前瀏覽器獲取對(duì)ajax連接對(duì)象的引用
var xhr=(function(){
try {
// 所有現(xiàn)代瀏覽器所使用的標(biāo)準(zhǔn)方法
return new XMLHttpRequest();
}catch(e){}
// 較老版本的internet Explorer兼容
try{
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
}catch(e){}
try{
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
}catch(e){}
try{
return new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){}
// 如果沒(méi)能找到相關(guān)的ajax連接對(duì)象,則跑出一個(gè)錯(cuò)誤。
throw new Error("Ajax not support in this browser.")
}()),
STATE_LOADED=4,
STATUS_OK=200;
// 一但從服務(wù)器收到表示成功的相應(yīng)消息,則執(zhí)行所給定的回調(diào)方法
xhr.onreadystatechange=function{
if(xhr.readyState !==STATE_LOADED){
return;
}
if(xhr.state==STATUS_OK){
callback(xhr.responseText);
}
}
// 使用瀏覽器的ajax連接對(duì)象來(lái)向所給定的URL發(fā)出相關(guān)的調(diào)用
xhr.open(type.toUpperCase(),url);
xhr.send(data);
}
// 使用方法
ajaxCall("get","/user/12345",function(rs){
alert('收到的數(shù)據(jù)為:'+rs);
})
應(yīng)用場(chǎng)景:
當(dāng)需要通過(guò)一個(gè)單獨(dú)的函數(shù)或方法來(lái)訪問(wèn)一系列的函數(shù)或方法調(diào)用,以簡(jiǎn)化代碼庫(kù)的其余內(nèi)容,使得代碼更容易跟蹤管理或者更好的維護(hù)時(shí),可以使用外觀模式。其實(shí)我們平時(shí)代碼中這種模式應(yīng)該是用的比較多的。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
- JavaScript設(shè)計(jì)模式--簡(jiǎn)單工廠模式定義與應(yīng)用案例詳解
- javascript設(shè)計(jì)模式 – 簡(jiǎn)單工廠模式原理與應(yīng)用實(shí)例分析
- Javascript設(shè)計(jì)模式理論與編程實(shí)戰(zhàn)之簡(jiǎn)單工廠模式
- JS面向?qū)ο蠡A(chǔ)講解(工廠模式、構(gòu)造函數(shù)模式、原型模式、混合模式、動(dòng)態(tài)原型模式)
- js面向?qū)ο笾R?jiàn)創(chuàng)建對(duì)象的幾種方式(工廠模式、構(gòu)造函數(shù)模式、原型模式)
- JavaScript 模式之工廠模式(Factory)應(yīng)用介紹
- javascript 模式設(shè)計(jì)之工廠模式學(xué)習(xí)心得
- JavaScript創(chuàng)建對(duì)象方式總結(jié)【工廠模式、構(gòu)造函數(shù)模式、原型模式等】
- JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布者-訂閱者模式)
- 常用的Javascript設(shè)計(jì)模式小結(jié)
- JavaScript設(shè)計(jì)模式--簡(jiǎn)單工廠模式實(shí)例分析【XHR工廠案例】
相關(guān)文章
JavaScript判斷用戶是否對(duì)表單進(jìn)行了修改的方法
這篇文章主要介紹了JavaScript判斷用戶是否對(duì)表單進(jìn)行了修改的方法,實(shí)例分析了javascript對(duì)表單操作與判定的技巧,需要的朋友可以參考下2015-03-03
viewer.js一個(gè)強(qiáng)大的基于jQuery的圖像查看插件(支持旋轉(zhuǎn)、縮放)
這篇文章主要介紹了Viewer這一款強(qiáng)大的 jQuery 圖像瀏覽插件,在信息詳情頁(yè)面實(shí)現(xiàn)點(diǎn)擊圖片可以預(yù)覽,腳本之家也是用的這個(gè)js,這里為分享一下使用方法,需要的朋友可以參考下2020-04-04
關(guān)于動(dòng)態(tài)執(zhí)行代碼(js的Eval)實(shí)例詳解
下面小編就為大家?guī)?lái)一篇關(guān)于動(dòng)態(tài)執(zhí)行代碼(js的Eval)實(shí)例詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
JavaScript面向?qū)ο笕齻€(gè)基本特征實(shí)例詳解【封裝、繼承與多態(tài)】
這篇文章主要介紹了JavaScript面向?qū)ο笕齻€(gè)基本特征,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript面向?qū)ο笕齻€(gè)基本特征封裝、繼承與多態(tài)的概念、原理、用法與操作注意事項(xiàng),需要的朋友可以參考下2020-05-05
JavaScript最完整的深淺拷貝實(shí)現(xiàn)方式詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript最完整的深淺拷貝實(shí)現(xiàn)方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02
JS之延時(shí)器和定時(shí)器執(zhí)行示例詳解
這篇文章主要為大家介紹了JS之延時(shí)器和定時(shí)器執(zhí)行示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

