開(kāi)放封閉原則:
開(kāi)放性:當(dāng)有新需求時(shí)疚顷,可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展壮池,在不影響現(xiàn)有功能的前提下,來(lái)實(shí)現(xiàn)新需求份乒;
封閉性:模塊的源代碼不能被修改恕汇,神圣不可侵犯(前提是功能是完整無(wú)誤的,修復(fù)bug不算破壞封閉性原則)或辖;
內(nèi)聚性/耦合性
內(nèi)聚性:表示單個(gè)模塊內(nèi)功能性強(qiáng)度性的度量瘾英;若一個(gè)模塊各個(gè)元素之間聯(lián)系很強(qiáng),那么該模塊就具有高內(nèi)聚颂暇,相反就是低內(nèi)聚缺谴;
耦合性:表示各個(gè)模塊之間聯(lián)系性的度量;若各個(gè)模塊聯(lián)系性很強(qiáng)耳鸯,那么各個(gè)模塊的耦合性很高湿蛔,相反就是低耦合;
總結(jié):一個(gè)好的程序架構(gòu)县爬,一般遵循高內(nèi)聚低耦合阳啥,這樣就能對(duì)各模塊進(jìn)行擴(kuò)展和復(fù)用,代碼質(zhì)量就比較高财喳;
1.工廠/構(gòu)造者/原型模式
工廠/構(gòu)造者/原型模式的共同點(diǎn)在于實(shí)現(xiàn)封裝性察迟,達(dá)到程序的復(fù)用。提高開(kāi)發(fā)效率耳高;不同點(diǎn)在于實(shí)現(xiàn)的方式不一致扎瓶;代碼如下:
/*
*定義工廠模式
*通過(guò)函數(shù)封裝某功能代碼,以達(dá)到復(fù)用
*/
function testOne(){
var obj={
name:"工廠模式"
};
obj.setName=function(name){
this.name=name;
}
return obj;
}
//執(zhí)行函數(shù)
testOne().setName("改變了");
/*
*定義構(gòu)造者模式
*學(xué)過(guò)Java的知道泌枪,每個(gè)類中都有構(gòu)造函數(shù)概荷,JavaScript不是面向?qū)ο笳Z(yǔ)言
*但是它也可以實(shí)現(xiàn),并通過(guò)new關(guān)鍵字實(shí)例化
*/
function testTwo(){
this.name="構(gòu)造者模式";
this.setName=function(name){
this.name=name;
}
}
//執(zhí)行
var testObj=new testTwo();
testObj.setName("改變了");
/*
*定義原型模式
*通過(guò)原型鏈的形式實(shí)現(xiàn)功能的封裝
*/
function testTwo(){
this.name="原型模式";
}
testTwo.prototype.setName=function(name){
this.name=name;
}
//執(zhí)行
var testObj=new testTwo();
testObj.setName("改變了");
2.單例模式:
保證一個(gè)類只有一個(gè)實(shí)例碌燕,在實(shí)例化類之前先判斷該實(shí)例是否存在误证,如果存在直接引入继薛,不存在就進(jìn)行實(shí)例化類;在JavaScript中雷厂,單例模式類作為一個(gè)命名空間提供者,從全局命名空間里提供一個(gè)唯一的訪問(wèn)點(diǎn)來(lái)訪問(wèn)該對(duì)象叠殷;通常采用自執(zhí)行匿名函數(shù)和閉包方式實(shí)現(xiàn)改鲫;代碼如下:
/*定義單例模式*/
var single=(function(){//自執(zhí)行匿名函數(shù)
var obj=null;
/*1.訪問(wèn)函數(shù)外面的變量;2.把變量保存在內(nèi)存中林束,不讓變量被回收像棘;
**2.特點(diǎn):函數(shù)1里面套函數(shù)2,然后函數(shù)1返回函數(shù)2壶冒;
**3.缺點(diǎn):容易吃內(nèi)存缕题,性能毛病胖腾;故閉包不用就將里面的變量全部null掉
*/
function Constructor(){
//dothing~~~
}
return {
testSingle:function(){
if(obj==null){
obj=new Constructor();
}
return obj;
}
}
})();
//執(zhí)行單例模式代碼
single.testSingle();
以上是單例模式的一種烟零,具體根據(jù)需求衍生出不同的單例模式;記住單例模式的核心:一個(gè)類只能有一個(gè)實(shí)例咸作;以上單例模式不管在什么時(shí)候都會(huì)執(zhí)行一次锨阿;因?yàn)椴捎昧俗詧?zhí)行匿名函數(shù)。如果想在有需要的時(shí)候執(zhí)行记罚,該怎么做墅诡?
惰性單例模式
var signle=function(funs){
var obj=null;
return function(){
return obj || (obj=funs.apply(this,arguments));
}
}
3.代理模式
“代理”生產(chǎn)商和消費(fèi)者之間有個(gè)代理商,用來(lái)聯(lián)系生產(chǎn)商和消費(fèi)者的聯(lián)系桐智,進(jìn)行商品交易末早。代理商要有生產(chǎn)商所提供的的信息展示給消費(fèi)者(程序中稱為接口);
- 真實(shí)角色:代理角色所代表的真實(shí)對(duì)象说庭,是我們最終要引用的對(duì)象然磷。
- 代理角色:代理對(duì)象角色內(nèi)部含有對(duì)真實(shí)對(duì)象的引用,從而可以操作真實(shí)對(duì)象刊驴,同時(shí)代理對(duì)象提供與真實(shí)對(duì)象相同的接口以便在任何時(shí)刻都能代替真實(shí)對(duì)象样屠。同時(shí),代理對(duì)象可以在執(zhí)行真實(shí)對(duì)象操作時(shí)缺脉,附加其他的操作痪欲,相當(dāng)于對(duì)真實(shí)對(duì)象進(jìn)行封裝。
代理模式的一個(gè)好處就是對(duì)外部提供統(tǒng)一的接口方法攻礼,而代理類在接口中實(shí)現(xiàn)對(duì)真實(shí)類的附加操作行為业踢,從而可以在不影響外部調(diào)用情況下,進(jìn)行系統(tǒng)擴(kuò)展礁扮。也就是說(shuō)知举,我要修改真實(shí)角色的操作的時(shí)候瞬沦,盡量不要修改他,而是在外部在“包”一層進(jìn)行附加行為雇锡,即代理類逛钻。
var factory_obj={//定義真實(shí)對(duì)象
name:"test",
address:"中國(guó)北京",
setName:function(name){
this.name=name;
},
showName:function(){
return this.name
},
setAddress:function(addr){
this.address=addr;
},
showAddress:function(){
return this.address;
}
};
var agent_obj={//定義代理對(duì)象
setName:function(name){
factory_obj.setName(name);
},
showName:function(){
return factory_obj.name;
},
setAddress:function(addr){
factory_obj.setAddress(addr);
},
showAddress:function(){
return factory_obj.address;
}
}
//定義使用者
//通過(guò)調(diào)用代理對(duì)象agent_obj來(lái)執(zhí)行factory_obj對(duì)象
agent_obj.setName("我是消費(fèi)者1");
console.log(agent_obj.showName());
agent_obj.setAddress("江西上饒");
console.log(agent_obj.address);
總結(jié):在代理模式中一定要同時(shí)具備真實(shí)對(duì)象和代理對(duì)象,真實(shí)對(duì)象是實(shí)際需要操作的對(duì)象锰提,代理對(duì)象是一個(gè)能訪問(wèn)到真實(shí)對(duì)象的接口曙痘。他們相互依賴;
優(yōu)點(diǎn):可以在不影響真實(shí)對(duì)象的基礎(chǔ)上進(jìn)行其他功能擴(kuò)展立肘;保持真實(shí)對(duì)象的完整性边坤,符合開(kāi)放封閉原則;在以上代碼進(jìn)行功能擴(kuò)展:
//擴(kuò)展age屬性谅年,并定義setAge和showAge方法
agent_obj['age']="16";
agent_obj['setAge']=function(age){
this.age=age;
}
age_obj['showAge']=function(){
return this.age;
}
4.發(fā)布/訂閱者模式
發(fā)布/訂閱者模式主要是為了松散耦合茧痒,提高代碼質(zhì)量;它大致?lián)碛小鞍l(fā)布者”和“訂閱者”這兩個(gè)角色融蹂;訂閱者關(guān)注了某發(fā)布者后旺订,當(dāng)發(fā)布者發(fā)布最新?tīng)顟B(tài),則訂閱就會(huì)收到通知超燃,并作出相應(yīng)的動(dòng)作耸峭;
場(chǎng)景實(shí)例:現(xiàn)在文章類APP都有對(duì)文章作者進(jìn)行關(guān)注的功能,關(guān)注之后淋纲,當(dāng)文章作者發(fā)布新文章時(shí)劳闹,系統(tǒng)就會(huì)通知你文章更新了。
(function(){
var manageObj={}; //注冊(cè)管理中心
var Publish=function(){//注冊(cè)發(fā)布者
}
var Subscribe=function(){//注冊(cè)訂閱者
return this;
}
/**
* 注冊(cè)訂閱事件
* @param type:string 訂閱的標(biāo)識(shí)
* @param funs:function 訂閱標(biāo)識(shí)的回調(diào)函數(shù)
**/
Subscribe.prototype.add=function(type,funs){
if(typeof type == "string"){
manageObj[type]=funs;
}else{
console.error("add(type:string,funs:function)參數(shù)類型Error");
}
}
/**
* 取消訂閱事件
* @param type:string 訂閱的標(biāo)識(shí)
**/
Subscribe.prototype.remove=function(type){
if(typeof type == "string"){
var keys=Object.keys(manageObj);
for(var i=0;i=keys.length;i++){
if(keys[i] == type){
delete manageObj[types];
break;
}
}
}else{
console.error("remove(type:string)參數(shù)類型Error");
}
}
/**
* 觸發(fā)訂閱事件
* @param type:string 訂閱的標(biāo)識(shí)
**/
Subscribe.prototype.trigger=function(type){
if(typeof type == "string"){
if(typeof manageObj[type] == "undefined"){
console.error(type+"沒(méi)有訂閱事件");
}else{
manageObj[type]();
}
}else{
console.error("trigger(type:string)參數(shù)類型Error");
}
}
//實(shí)例化Subscribe
var subObj=new Subscribe();
subObj.add("definedEvent",function(){
console.log("我是自定義事件");
});
subObj.trigger("definedEvent");
})();