一惧互、設(shè)計(jì)模式
javascript里面給我們提供了很多種設(shè)計(jì)模式:
工廠哎媚、橋、組合喊儡、門面拨与、適配器、裝飾者艾猜、享元买喧、代理、觀察者匆赃、命令淤毛、責(zé)任鏈
在前面我們實(shí)現(xiàn)了工廠模式和橋模式
工廠模式 :
核心:為了生產(chǎn)對(duì)象,實(shí)現(xiàn)解耦算柳。
橋接模式 :
(橋接模式是一種既能把兩個(gè)對(duì)象連接在一起低淡,又能避免二者間的強(qiáng)耦合的方法。通過“橋”把彼此聯(lián)系起來,同時(shí)又允許他們各自獨(dú)立變化)
主要作用:主要作用表現(xiàn)為將抽象與其實(shí)現(xiàn)隔離開來蔗蹋,以便二者獨(dú)立化事期。
組合模式 :
(組合模式是一種專門為創(chuàng)建Web上的動(dòng)態(tài)用戶界面而量身制定的模式。使用這種模式可以用一條命令在多個(gè)對(duì)象上激發(fā)復(fù)雜的或遞歸的行為纸颜。這可以簡化粘合性代碼兽泣,使其更容易維護(hù),而那些復(fù)雜行為則被委托給各個(gè)對(duì)象胁孙。)
優(yōu)點(diǎn) :
1 你可以用同樣的方法處理對(duì)象的集合與其中的特定子對(duì)象唠倦。
2 它可以用來把一批子對(duì)象組織成樹形結(jié)構(gòu),并且使整棵樹都可以被遍歷涮较。
場景 :
1 存在一批組織成某種層次體系的對(duì)象
2 希望對(duì)這批對(duì)象或其中的一部分對(duì)象實(shí)施一個(gè)操作稠鼻。
特點(diǎn) :
1 組合模式中只有兩種類型對(duì)象:組合對(duì)象、葉子對(duì)象
2 這兩種類型都實(shí)現(xiàn)同一批接口
3 一般我們會(huì)在組合對(duì)象中調(diào)用其方法并隱式調(diào)用"下級(jí)對(duì)象"的方法(這里我們一般采用遞歸的形式去做)
門面模式
兩個(gè)作用:
1狂票、簡化類的接口
2候齿、消除類與使用它的客戶代碼之間的耦合
門面模式常常是開發(fā)人員最親密的朋友。它幾乎是所有javascript庫的核心原則
門面模式的目的是為了讓開發(fā)人員用更簡單的方法調(diào)用一些相對(duì)復(fù)雜或組合的方法闺属,主要就是簡化開發(fā)的復(fù)雜性慌盯,提供一個(gè)相對(duì)容易的API去調(diào)用內(nèi)部的方法供外界去使用,這樣程序員開發(fā)會(huì)變得輕松些掂器,編寫一次組合代碼后可以反復(fù)的去使用它亚皂,有助于節(jié)省時(shí)間和精力
注意:
不要濫用門面模式,所以使用你心儀的門面之前一定要三思而定国瓮,搞不好你就會(huì)小題大做
適配器設(shè)計(jì)
1灭必、適配器模式可用來在現(xiàn)有的接口和不兼容的類之間進(jìn)行適配。
使用這種模式的對(duì)象又叫做包裝器(wrapper)乃摹,因?yàn)樗麄兪窃谟靡粋€(gè)新的接口包裝另一個(gè)對(duì)象禁漓。
借助適配器可以處理一些類與API不匹配、不能一同使用的情況孵睬。
2播歼、注意適配器和門面雖然比較類似,但是門面模式只是為了簡化一個(gè)接口肪康,
它并不是提供額外的選擇荚恶,適配器則要把一個(gè)接口轉(zhuǎn)換為另一個(gè)接口,
它并不會(huì)濾除某些能力磷支,也不會(huì)簡化接口谒撼。
裝飾者模式
是一種為對(duì)象添加新特性的技術(shù),它并不適用創(chuàng)建新子類的這種手段。裝飾者模式可以用來透明的把原始對(duì)象包裝在具有同樣接口的另一個(gè)對(duì)象之中雾狈。這樣我們就可以為對(duì)象添加一個(gè)方法或者一些行為廓潜,然后將方法調(diào)用傳遞給原始對(duì)象
特性:
1、實(shí)現(xiàn)同樣的接口
2、需要有子類
講解都在代碼中:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<title>裝飾者設(shè)計(jì)模式</title>
<!--
@theme: javascript高級(jí) 裝飾者設(shè)計(jì)模式
@autor:EthanCoco
@date:2015-11-24
@email:lijianlin0204@163.com
-->
</head>
<body>
<script type=text/javascript charset=utf-8>
//這個(gè)就不繼續(xù)說了
var LJL = {};
LJL.Interface = function(name,methods){
if(arguments.length !== 2){
throw new Error("the param must have two");
}
this.name = name;
this.methods = [];
for(var i=0;i<methods.length;i++){
if(typeof methods[i] !=='string'){
throw new Error("the type of param must be string");
}
this.methods.push(methods[i]);
}
};
LJL.Interface.checkMethodsIsPass = function(object){
if(arguments.length < 2){
throw new Error("the checkMethodsIsPass methods must more then 1 param");
}
for(var i=1;i<arguments.length;i++){
var instanceInterface = arguments[i];
if( instanceInterface.constructor !== LJL.Interface){
throw new Error("the param is not a Interface");
}
for(var j=0;j<instanceInterface.methods.length;j++){
var methodName = instanceInterface.methods[j];
if(!object[methodName] || typeof object[methodName] !== 'function'){
throw new Error("the methods not come pass!")
}
}
}
};
LJL.extends = function(sub,sup){
var F = new Function();
F.prototype = sup.prototype;
sub.prototype = new F();
sub.prototype.constructor = sub;
sub.superClass = sup.prototype;
if(sup.prototype.constructor == Object.prototype.constructor){
sup.prototype.constructor = sup ;
}
};
//裝飾者設(shè)計(jì)模式:
/**
簡單理解就是:在保證不改變?cè)袑?duì)象的基礎(chǔ)上辩蛋,去擴(kuò)展一些想要的方法或需求
在子類的基礎(chǔ)上要實(shí)現(xiàn)相同的接口
特性:
1呻畸、實(shí)現(xiàn)同樣的接口
2、需要有子類
*/
//裝飾者模式示例
/**裝飾者概念:
裝飾者:(decorator)[是一種為對(duì)象添加新特性的技術(shù)],
它并不適用創(chuàng)建新子類的這種手段悼院。
裝飾者模式可以用來透明的[把原始對(duì)象包裝在具有同樣接口的另一個(gè)對(duì)象之中]伤为。
這樣我們就可以為對(duì)象添加一個(gè)方法或者一些行為,
然后將方法調(diào)用傳遞給原始對(duì)象据途。
*/
/**
整體思路講解
//場景:我要獲得電腦的價(jià)格和電腦的類型=视蕖(裸機(jī))
創(chuàng)建一個(gè)接口對(duì)象
var ComputerInterface = new LJL.Interface('ComputerInterface',['getPrice','getType']);
創(chuàng)建一個(gè)對(duì)象
var Computer =function(){
//檢驗(yàn)接口
LJL.Interface.checkMethodsIsPass(this,ComputerInterface);
};
//在原型對(duì)象上添加方法
Computer.prototype = {
constructor : Computer,//還原構(gòu)造器
getPrice : function(){//實(shí)現(xiàn)接口的getPrice方法
return 4500;
},
getType : function(){//實(shí)現(xiàn)接口的getType方法
document.write("this is a assamable");
}
};
//好了,現(xiàn)在我有一個(gè)新的需求:這個(gè)電腦不滿足我的需求颖医,我還要加個(gè)內(nèi)存條位衩,你給我算算一共要多少錢?
//你難道要在開始的對(duì)象上加價(jià)格么熔萧?這樣就改變了原始對(duì)象糖驴,如果一個(gè)人就要裸機(jī)呢?你難道又要把原始對(duì)象改回來么佛致?
//這樣做顯然是不合理的
//為此我們用裝飾者模式來實(shí)現(xiàn)這一功能贮缕,就是我在原始對(duì)象上在套一層,既不影響原始對(duì)象性晌杰,也不影響后加上的對(duì)象
//兩者都是獨(dú)立的跷睦,但又是存在關(guān)聯(lián)的
//創(chuàng)建一個(gè)新的對(duì)象來裝飾原始對(duì)象
var CpuDecorator = function(computer){//新的對(duì)象,裝飾誰肋演?我們傳一個(gè)參數(shù),表示原始對(duì)象的實(shí)例對(duì)象
//借用構(gòu)造函數(shù)繼承原始對(duì)象
CpuDecorator.superClass.constructor.call(this,computer);
};
//既然有了個(gè)參數(shù)烂琴,這個(gè)參數(shù)該如何或者說從哪里獲得爹殊?
////////////////////////////////////////
//我們可以給原始對(duì)象一個(gè)屬性:修改成如下
var Computer =function(computer){
//這個(gè)屬性就是為了讓子類繼承的 (讓子類 多一個(gè)父類的引用)
this.computer = computer;//添加一個(gè)屬性
//檢驗(yàn)接口
LJL.Interface.checkMethodsIsPass(this,ComputerInterface);
};
/////////////////////////////////////////////////
//然后我們用子類繼承父類
LJL.extends(CpuDecorator,Computer);//原型繼承 (說明:這個(gè)繼承用來實(shí)現(xiàn)同一個(gè)接口的方法,這是裝飾者模式的特性)
//在原型對(duì)象上實(shí)現(xiàn)同樣的方法
CpuDecorator.prototype = {
constructor : CpuDecorator,
getPrice : function(){
return this.computer.getPrice()+1000;//在原有的對(duì)象上的價(jià)格加上cpu的價(jià)格奸绷,得最終價(jià)格
},
getType : function(){
document.write("this is a plus a cpu"+"<br/>");
}
};
*/
//以下為完整實(shí)例以及測試
var ComputerInterface = new LJL.Interface('ComputerInterface',['getPrice','getType']);
var Computer =function(computer){
this.computer = computer;
LJL.Interface.checkMethodsIsPass(this,ComputerInterface);
};
Computer.prototype = {
constructor : Computer,
getPrice : function(){
return 4500;
},
getType : function(){
document.write("this is a assamable");
}
};
var CpuDecorator = function(computer){
CpuDecorator.superClass.constructor.call(this,computer);
};
LJL.extends(CpuDecorator,Computer);
CpuDecorator.prototype = {
constructor : CpuDecorator,
getPrice : function(){
return this.computer.getPrice()+1000;
},
getType : function(){
document.write("this is a plus a cpu"+"<br/>");
}
};
var com = new Computer();
alert(com.getPrice());
com.getType();
com = new CpuDecorator(com);
document.write(com.getPrice()+"<br/>");
com.getType();
//裝飾者 不僅可以用在類上梗夸, 還可以用在函數(shù)上
//返回一個(gè)當(dāng)前時(shí)間的字符串表示形式
function getDate(){
return (new Date()).toString();
};
// 包裝函數(shù) (裝飾者函數(shù))
function upperCaseDecorator(fn){
return function(){
return fn.apply(this, arguments).toUpperCase();
}
};
alert(getDate());
var getDecoratorDate = upperCaseDecorator(getDate);
alert(getDecoratorDate());
</script>
</body>
</html>