最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript面向?qū)ο笾叽蠡驹瓌t實(shí)例詳解

 更新時(shí)間:2020年05月06日 11:59:27   作者:Aaron  
這篇文章主要介紹了JavaScript面向?qū)ο笾叽蠡驹瓌t,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript面向?qū)ο笃叽蠡驹瓌t,包括單一職責(zé)、開閉原則、里氏替換、依賴倒置、接口隔離、迪米特法則及組合/聚合復(fù)用原則,需要的朋友可以參考下

本文實(shí)例講述了JavaScript面向?qū)ο笾叽蠡驹瓌t。分享給大家供大家參考,具體如下:

面向?qū)ο缶幊逃凶约旱奶匦耘c原則,如果對于面向?qū)ο笥幸恍┝私獾脑?,面向?qū)ο笕筇卣鳎庋b、繼承、多態(tài),如果對面向?qū)@三個(gè)概念不太了解,請參考面向?qū)ο笾齻€(gè)基本特征(javaScript)

單一職責(zé)

如果我們在編寫程序的時(shí)候,一類或者一個(gè)方法里面包含了太多方法,對于代碼的可讀性來說,無非是一場災(zāi)難,對于我們來說。所以為了解決這個(gè)問題,出現(xiàn)了單一職責(zé)。

什么是單一職責(zé)

單一職責(zé):又稱單一功能原則,面向?qū)ο笪鍌€(gè)基本原則(SOLID)之一。它規(guī)定一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因。(節(jié)選自百度百科)

按照上面說的,就是對一個(gè)類而言,應(yīng)該僅有一個(gè)引起它變化的原因。換句話說,一個(gè)類的功能要單一,只做與它相關(guān)的事情。在類的設(shè)計(jì)過程中要按職責(zé)進(jìn)行設(shè)計(jì),彼此保持正交,互不干涉。

單一職責(zé)的好處
  1. 類的復(fù)雜性降低,實(shí)現(xiàn)什么職責(zé)都有清晰明確的定義
  2. 可讀性提高,復(fù)雜性降低,那當(dāng)然可讀性提高了
  3. 可維護(hù)性提高,可讀性提高,那當(dāng)然更容易維護(hù)了
  4. 變更引起的風(fēng)險(xiǎn)降低,變更是必不可少的,如果接口的單一職責(zé)做得好,一個(gè)接口修改只對相應(yīng)的實(shí)現(xiàn)類有影響,對其他的接口無影響,這對系統(tǒng)的擴(kuò)展性、維護(hù)性都有非常大的幫助。
實(shí)例
class ShoppinCar {
  constructor(){
    this.goods = [];
  }
  addGoods(good){
    this.goods = [good];
  }
  getGoodsList(){
    return this.goods;
  }
}
class Settlement {
  constructor(){
    this.result = 0; 
  }
  calculatePrice(list,key){
    let allPrice = 0;
    list.forEach((el) => {
      allPrice += el[key];
    })
    this.result = allPrice;
  }
  getAllPrice(){
    return this.result;
  }
}

用上面的代碼來說ShoppinCar類存在兩個(gè)方法addGoodsgetGoodsList,分別是添加商品和獲取商品列表。Settlement類中存在兩個(gè)方法calculatePricegetAllPrice分別做的事情是計(jì)算價(jià)錢與獲取總價(jià)錢。ShoppinCarSettlement都是在做自己的事情。添加商品與計(jì)算價(jià)格,雖然在業(yè)務(wù)上是相互依賴的,但是在代碼中分別用兩個(gè)類,然他們自己做自己的事情。其中任何一個(gè)類更改不會(huì)對另一個(gè)類進(jìn)行更改。

開閉原則

在一個(gè)類中暴露出去的方法,若這個(gè)方法變更了,則會(huì)產(chǎn)生很大的后果,可能導(dǎo)致其他依賴于這個(gè)方法且有不需要變更的業(yè)務(wù)造成大面積癱瘓。為了解決這個(gè)問題,可以單獨(dú)再寫一個(gè)方法,若這個(gè)方法與這個(gè)類中的其他方法相互依賴。

解決辦法:

  1. 把其中依賴的代碼copy一份到新的類中。
  2. 在新類中引用舊類中的方法。

兩種方法都不是最好的解決方案。

第一種方法會(huì)導(dǎo)致代碼大量的重復(fù),第二種方法會(huì)導(dǎo)致類與類之間互相依賴。

什么是開閉原則

開閉原則:“軟件中的對象(類,模塊,函數(shù)等等)應(yīng)該對于擴(kuò)展是開放的,但是對于修改是封閉的”,這意味著一個(gè)實(shí)體是允許在不改變它的源代碼的前提下變更它的行為。(節(jié)選自百度百科)

開閉原則對擴(kuò)展開放,對修改關(guān)閉,并不意味著不做任何修改,底層模塊的變更,必然要有高層模塊進(jìn)行耦合,否則就是一個(gè)孤立無意義的代碼片段。開閉原則是一個(gè)最基本的原則,另外六個(gè)原則都是開閉原則的具體形態(tài),是指導(dǎo)設(shè)計(jì)的工具和方法,而開閉原則才是精神領(lǐng)袖.

開閉原則好處
  1. 開閉原則有利于進(jìn)行單元測試
  2. 開閉原則可以提高復(fù)用性
  3. 開閉原則可以提高可維護(hù)性
  4. 面向?qū)ο箝_發(fā)的要求
實(shí)例
class Drag {
  down(){
    // ...
  }  
  move(){
    // ...
    // 對拖拽沒有做任何限制可以隨意拖拽
  }  
  up(){
    // ...
  } 
}
class LimitDrag extends Drag {
  move(){
    // ...
    // 重寫該方法對拖拽進(jìn)行限制處理
  }
}

LimitDrag中重寫了move方法,若修改了可以滿足兩種需求,一種是限制型拖拽,一種是不限制型拖拽,任何一個(gè)更改了另外一個(gè)還是可以正常運(yùn)行。

里氏替換

每個(gè)開發(fā)人員在使用別人的組件時(shí),只需知道組件的對外裸露的接口,那就是它全部行為的集合,至于內(nèi)部到底是怎么實(shí)現(xiàn)的,無法知道,也無須知道。所以,對于使用者而言,它只能通過接口實(shí)現(xiàn)自己的預(yù)期,如果組件接口提供的行為與使用者的預(yù)期不符,錯(cuò)誤便產(chǎn)生了。里氏替換原則就是在設(shè)計(jì)時(shí)避免出現(xiàn)派生類與基類不一致的行為。

什么是里氏替換

里氏替換原則:OCP作為OO的高層原則,主張使用“抽象(Abstraction)”和“多態(tài)(Polymorphism)”將設(shè)計(jì)中的靜態(tài)結(jié)構(gòu)改為動(dòng)態(tài)結(jié)構(gòu),維持設(shè)計(jì)的封閉性。“抽象”是語言提供的功能?!岸鄳B(tài)”由繼承語義實(shí)現(xiàn)。(節(jié)選自百度百科)

里氏替換好處
  1. 代碼共享,減少創(chuàng)建類的工作量,每個(gè)子類都擁有父類的方法和屬性
  2. 提高代碼的重用性
  3. 子類可以形似父類,但是又異于父類。
  4. 提高代碼的可擴(kuò)展性,實(shí)現(xiàn)父類的方法就可以了。許多開源框架的擴(kuò)展接口都是通過繼承父類來完成。
  5. 提高產(chǎn)品或項(xiàng)目的開放性
實(shí)例
// 抽象槍類
class AbstractGun {
  shoot(){
    throw "Abstract methods cannot be called";
  }
}
// 步槍
class Rifle extends AbstractGun {
  shoot(){
    console.log("步槍射擊...");
  }
}
// 狙擊槍
class AUG extends Rifle {
  zoomOut(){
    console.log("通過放大鏡觀察");
  }
  shoot(){
    console.log("AUG射擊...");
  }
}
// 士兵
class Soldier {
  constructor(){
    this.gun = null;
  }
  setGun(gun){
    this.gun = gun;
  }
  killEnemy(){
    if(!this.gun){
      throw "需要給我一把槍";
      return;
    }
    console.log("士兵開始射擊...");
    this.gun.shoot();
  }
}
// 狙擊手
class Snipper extends Soldier {
  killEnemy(aug){
    if(!this.gun){
      throw "需要給我一把槍";
      return;
    }
    this.gun.zoomOut();
    this.gun.shoot();
  }
}
let soldier = new Soldier();
soldier.setGun(new Rifle());
soldier.killEnemy();

let snipper = new Snipper();
// 分配狙擊槍
snipper.setGun(new AUG());
snipper.killEnemy();

snipper.setGun(new Rifle());
// snipper.killEnemy(); // this.gun.zoomOut is not a function

從上述代碼中可以看出,子類和父類之間關(guān)系,子類方法一定是等于或大于父類的方法。子類能夠出現(xiàn)的父類不一定能出現(xiàn),但是父類出現(xiàn)的地方子類一定能夠出現(xiàn)。

依賴倒置

如果方法與方法之間或類與類之間,存在太多的依賴關(guān)系會(huì)導(dǎo)致代碼可讀性以及可維護(hù)性很差。依賴倒置原則能夠很好的解決這些問題。

什么是依賴倒置

依賴倒置原則:程序要依賴于抽象接口,不要依賴于具體實(shí)現(xiàn)。簡單的說就是要求對抽象進(jìn)行編程,不要對實(shí)現(xiàn)進(jìn)行編程,這樣就降低了客戶與實(shí)現(xiàn)模塊間的耦合。(節(jié)選自百度百科)

  1. 高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象
  2. 抽象不應(yīng)該依賴細(xì)節(jié)
  3. 細(xì)節(jié)應(yīng)該依賴抽象
依賴倒置好處
  1. 通過依賴于接口,隔離了具體實(shí)現(xiàn)類
  2. 低一層的變動(dòng)并不會(huì)導(dǎo)致高一層的變動(dòng)
  3. 提高了代碼的容錯(cuò)性、擴(kuò)展性和易于維護(hù)
實(shí)例
// 抽象槍類
class AbstractGun {
  shoot(){
    throw "Abstract methods cannot be called";
  }
}
// 步槍
class Rifle extends AbstractGun {
  shoot(){
    console.log("步槍射擊...");
  }
}
// 狙擊槍
class AUG extends AbstractGun {
  shoot(){
    console.log("AUG射擊...");
  }
}

從上面的代碼可以看出,步槍與狙擊槍的shoot全部都是依賴于AbstractGun抽象的槍類,上述編程滿足了依賴倒置原則。

接口隔離

什么是接口隔離

接口隔離:客戶端不應(yīng)該依賴它不需要的接口;一個(gè)類對另一個(gè)類的依賴應(yīng)該建立在最小的接口上。(節(jié)選自百度百科)

接口隔離原則與單一職責(zé)原則的審視角度不相同。單一職責(zé)原則要求是類和接口的職責(zé)單一,注重的職責(zé),這是業(yè)務(wù)邏輯上的劃分。接口隔離原則要求接口的方法盡量少。

接口隔離好處
  1. 避免接口污染
  2. 提高靈活性
  3. 提供定制服務(wù)
  4. 實(shí)現(xiàn)高內(nèi)聚
實(shí)例
function mix(...mixins) {
 class Mix {}
 for (let mixin of mixins) {
  copyProperties(Mix, mixin);
  copyProperties(Mix.prototype, mixin.prototype);
 }
 return Mix;
}
function copyProperties(target, source) {
 for (let key of Reflect.ownKeys(source)) {
  if ( key !== "constructor"&& key !== "prototype"&& key !== "name") {
   let desc = Object.getOwnPropertyDescriptor(source, key);
   Object.defineProperty(target, key, desc);
  }
 }
}
class Behavior {
  eat(){
    throw "Abstract methods cannot be used";
  }  
  call(){
    throw "Abstract methods cannot be used";
  }
}
class Action {
  climbTree(){
    throw "Abstract methods cannot be used";
  }
}
class Dog extends Behavior{
  eat(food){
    console.log(`狗正在吃${food}`);
  }
  hungry(){
    console.log("汪汪汪,我餓了")
  }
}
const CatMin = mix(Behavior,Action);
class Cat extends CatMin{
  eat(food){
    console.log(`貓正在吃${food}`);
  }
  hungry(){
    console.log("喵喵喵,我餓了")
  }
  climbTree(){
    console.log("爬樹很開心哦~")
  }
}
let dog = new Dog();
dog.eat("骨頭");
dog.hungry();
let cat = new Cat();
cat.eat("魚");
cat.hungry();
cat.climbTree();

大家一定要好好分析一下上面的代碼,共有兩個(gè)抽象類,分別對應(yīng)不同的行為,CatDog類擁有共同的行為,但是Cat又擁有其自己單獨(dú)的行為,使用抽象(即接口)繼承其方法,使用接口隔離使其完成各自的工作,各司其職。

迪米特法則

迪米特法則:最少知識(shí)原則(Least Knowledge Principle 簡寫LKP),就是說一個(gè)對象應(yīng)當(dāng)對其他對象有盡可能少的了解,不和陌生人說話。英文簡寫為: LoD.(節(jié)選自百度百科)

迪米特法則的做法觀念就是類間解耦,弱耦合,只有弱耦合了以后,類的復(fù)用率才可以提高。一個(gè)類應(yīng)該對其他對象保持最少的了解。通俗來講,就是一個(gè)類對自己依賴的類知道的越少越好。因?yàn)轭惻c類之間的關(guān)系越密切,耦合度越大,當(dāng)一個(gè)類發(fā)生改變時(shí),對另一個(gè)類的影響也越大。

迪米特法則好處
  1. 減少對象之間的耦合性
實(shí)例
class ISystem {
  close(){
    throw "Abstract methods cannot be used";
  }
}
class System extends ISystem{
  saveCurrentTask(){
    console.log("saveCurrentTask")
  }
  closeService(){
    console.log("closeService")
  }
  closeScreen(){
    console.log("closeScreen")
  }
  closePower(){
    console.log("closePower")
  }
  close(){
    this.saveCurrentTask();
    this.closeService();
    this.closeScreen();
    this.closePower();
  }
}
class IContainer{
  sendCloseCommand(){
    throw "Abstract methods cannot be used";
  }
}
class Container extends IContainer{
  constructor(){
    super()
    this.system = new System();
  }
  sendCloseCommand(){
    this.system.close();
  }
}
class Person extends IContainer{
  constructor(){
    super();
    this.container = new Container();
  }
  clickCloseButton(){
    this.container.sendCloseCommand();
  }
}
let person = new Person();
person.clickCloseButton();

上面代碼中Container作為媒介,其調(diào)用類不知道其內(nèi)部是如何實(shí)現(xiàn),用戶去觸發(fā)按鈕,Container把消息通知給計(jì)算機(jī),計(jì)算機(jī)去執(zhí)行相對應(yīng)的命令。

組合/聚合復(fù)用原則

聚合(Aggregation)表示一種弱的‘擁有'關(guān)系,體現(xiàn)的是A對象可以包含B對象但B對象不是A對象的一部分。

合成(Composition)則是一種強(qiáng)的'擁有'關(guān)系,體現(xiàn)了嚴(yán)格的部分和整體關(guān)系,部分和整體的生命周期一樣。

組合/聚合:是通過獲得其他對象的引用,在運(yùn)行時(shí)刻動(dòng)態(tài)定義的,也就是在一個(gè)對象中保存其他對象的屬性,這種方式要求對象有良好定義的接口,并且這個(gè)接口也不經(jīng)常發(fā)生改變,而且對象只能通過接口來訪問,這樣我們并不破壞封裝性,所以只要類型一致,運(yùn)行時(shí)還可以通過一個(gè)對象替換另外一個(gè)對象。

優(yōu)先使用對象的合成/聚合將有助于你保持每個(gè)類被封裝,并被集中在單個(gè)任務(wù)上,這樣類和類繼承層次會(huì)保持較小規(guī)模,而且不太可能增長為不可控制的龐然大物。

組合/聚合復(fù)用原則好處
  1. 新的實(shí)現(xiàn)較為容易,因?yàn)槌惖拇蟛糠止δ芸赏ㄟ^繼承關(guān)系自動(dòng)進(jìn)入子類;
  2. 修改或擴(kuò)展繼承而來的實(shí)現(xiàn)較為容易。
實(shí)例
function mix(...mixins) {
 class Mix {}
 for (let mixin of mixins) {
  copyProperties(Mix, mixin);
  copyProperties(Mix.prototype, mixin.prototype);
 }
 return Mix;
}
function copyProperties(target, source) {
 for (let key of Reflect.ownKeys(source)) {
  if ( key !== "constructor"&& key !== "prototype"&& key !== "name") {
   let desc = Object.getOwnPropertyDescriptor(source, key);
   Object.defineProperty(target, key, desc);
  }
 }
}
class Savings {
  saveMoney(){
    console.log("存錢");
  }
  withdrawMoney(){
    console.log("取錢");
  }
}
class Credit {
  overdraft(){
    console.log("透支")
  }
}
const CarMin = mix(Savings,Credit);
class UserCar extends CarMin {
  constructor(num,carUserName){
    super();
    console.log()
    this.carNum = num;
    this.carUserName = carUserName;
  }
  getCarNum(){
    return this.carNum;
  }
  getCarUserName(){
    return this.carUserName;
  }
}
let myCar = new UserCar(123456798,"Aaron");
console.log(myCar.getCarNum());
console.log(myCar.getCarUserName());
myCar.saveMoney();
myCar.withdrawMoney();
myCar.overdraft();

總結(jié)

這些原則在設(shè)計(jì)模式中體現(xiàn)的淋淋盡致,設(shè)計(jì)模式就是實(shí)現(xiàn)了這些原則,從而達(dá)到了代碼復(fù)用、增強(qiáng)了系統(tǒng)的擴(kuò)展性。所以設(shè)計(jì)模式被很多人奉為經(jīng)典。我們可以通過好好的研究設(shè)計(jì)模式,來慢慢的體會(huì)這些設(shè)計(jì)原則。

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具http://tools.jb51.net/code/HtmlJsRun測試上述代碼運(yùn)行效果。

更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)

希望本文所述對大家JavaScript程序設(shè)計(jì)有所幫助。

相關(guān)文章

最新評論

万山特区| 桦川县| 突泉县| 曲周县| 阜南县| 福贡县| 高尔夫| 印江| 岳普湖县| 乌兰浩特市| 秦安县| 朝阳市| 侯马市| 恩平市| 玛沁县| 滨州市| 乐东| 栾川县| 察哈| 陆丰市| 金塔县| 桐城市| 东山县| 阜城县| 积石山| 乡城县| 永靖县| 通榆县| 勃利县| 万全县| 盘锦市| 积石山| 康马县| 大名县| 阳朔县| 武鸣县| 五大连池市| 临海市| 苏尼特右旗| 华安县| 伊通|