成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[譯]理解設(shè)計(jì)模式

NeverSayNever / 1282人閱讀

摘要:例如可以用構(gòu)造函數(shù)實(shí)現(xiàn)單例模式。例如當(dāng)這個(gè)構(gòu)造函數(shù)被調(diào)用,它會(huì)檢查是否存在。工廠模式工廠模式使用工廠方法創(chuàng)建對(duì)象,而不指定所創(chuàng)建對(duì)象的確切類或構(gòu)造函數(shù)。雖然了解審設(shè)計(jì)模式很重要,但是不要過(guò)度使用它們。

By Sukhjinder Arora | Oct 16, 2018

原文

當(dāng)你開始了一個(gè)新項(xiàng)目,你不會(huì)馬上開始編寫代碼。第一步,你必須定義這個(gè)項(xiàng)目解決什么問(wèn)題和適用范圍,然后列出這個(gè)項(xiàng)目的特性或者規(guī)格。在你開始編碼或者正在處理更復(fù)雜的項(xiàng)目之后,你應(yīng)該選擇最合適你項(xiàng)目的設(shè)計(jì)模式。

什么是設(shè)計(jì)模式

在軟件工程里,設(shè)計(jì)模式是軟件設(shè)計(jì)的一種常見問(wèn)題的可重用解決方案。設(shè)計(jì)模式是經(jīng)驗(yàn)豐富的軟件開發(fā)人員所使用的最佳實(shí)踐,可以認(rèn)為是編程模版。

為什么使用設(shè)計(jì)模式

許多程序員要么認(rèn)為使用設(shè)計(jì)模式是浪費(fèi)時(shí)間的,要么他們不知道如何正確使用設(shè)計(jì)模式。但是正確使用了設(shè)計(jì)模式會(huì)幫助你寫出可維護(hù)性高的代碼。

最重要的是,設(shè)計(jì)模式給軟件開發(fā)者共同的話題、術(shù)語(yǔ)。會(huì)讓學(xué)習(xí)了設(shè)計(jì)模式的初學(xué)者更快看懂你寫的代碼。

舉個(gè)例子,如果你在項(xiàng)目中使用了裝飾器模式,那么新來(lái)的程序員馬上知道你這段代碼正在做什么(譯者:前提是這名程序員知道這個(gè)設(shè)計(jì)模式),并且他們會(huì)更加專注解決業(yè)務(wù)問(wèn)題,而不是試圖理解這段代碼做的是什么。

現(xiàn)在我們知道什么是設(shè)計(jì)模式,并且知道了它們?yōu)槭裁茨敲粗匾?,讓我們開始深入各個(gè)應(yīng)用在js的設(shè)計(jì)模式吧。

*

模塊模式

模塊是一段獨(dú)立的代碼,因此我們可以在不影響其他代碼的情況下修改模塊的代碼。模塊還允許我們通過(guò)變量來(lái)創(chuàng)建多帶帶的范圍以避免命名空間的污染。當(dāng)模塊與其它代碼耦合度低時(shí)(譯者:類似用依賴導(dǎo)入第三方庫(kù)的那種程度),我們還可以在其他項(xiàng)目復(fù)用模塊。

模塊是任何js應(yīng)用程序不可或缺的一部分,有助于保持代碼高內(nèi)聚低耦合。有許多方法可以在JavaScript中創(chuàng)建模塊,其中一種是模塊模式。

不同于其它的編程語(yǔ)言,js沒有修飾符,也就是說(shuō)你無(wú)法將變量聲明為私有或公有。因此Module模式也用于模擬封裝的概念。

我們可以在js使用IIFE(立即調(diào)用函數(shù)表達(dá)式)、閉包、函數(shù)范圍來(lái)實(shí)現(xiàn)模塊。例子如下:

const myModule = (function() {
  
  const privateVariable = "Hello World";
  
  function privateMethod() {
    console.log(privateVariable);
  }
  return {
    publicMethod: function() {
      privateMethod();
    }
  }
})();
myModule.publicMethod();

由于是IIFE,代碼立即執(zhí)行,并返回對(duì)象給myModule對(duì)象。由于是閉包,即使IIFE執(zhí)行完成,但是返回的對(duì)象依然能夠訪問(wèn)IIFE內(nèi)定義的函數(shù)和變量。

因?yàn)椋贗IFE內(nèi)定義的變量和函數(shù)基本上在外部不能直接調(diào)用的,可以看作是myModule的私有的。

代碼執(zhí)行后,myModule變量像這樣:

const myModule = {
  publicMethod: function() {
    privateMethod();
  }};
  

因此,我們可以調(diào)用publicMethod方法,而它有調(diào)用privateMethod方法。例如:

// Prints "Hello World"
module.publicMethod();
揭示模塊模式

揭示模塊模式是經(jīng)Christian Heilmann基于模塊模式略微改進(jìn)的一種模式。模塊模式的問(wèn)題是我們必須創(chuàng)建公共的方法,然后才能通過(guò)這個(gè)公共的方法來(lái)調(diào)用私有變量和方法。在這個(gè)模式中,我們將返回對(duì)象的屬性映射到我們想要暴露出去的私有方法。這就是揭示模塊模式。例如:

const myRevealingModule = (function() {
  
  let privateVar = "Peter";
  const publicVar  = "Hello World";
  function privateFunction() {
    console.log("Name: "+ privateVar);
  }
  
  function publicSetName(name) {
    privateVar = name;
  }
  function publicGetName() {
    privateFunction();
  }
  /** reveal methods and variables by assigning them to object     properties */
return {
    setName: publicSetName,
    greeting: publicVar,
    getName: publicGetName
  };
})();
myRevealingModule.setName("Mark");
// prints Name: Mark
myRevealingModule.getName();

這種模式讓我們更容易理解我們可以公開訪問(wèn)那些方法和變量,這有助于提高代碼可讀性。

代碼執(zhí)行后,myRevealingModule像這樣:

const myRevealingModule = {
  setName: publicSetName,
  greeting: publicVar,
  getName: publicGetName
};

我們可以調(diào)用myRevealingModule.setName("Mark"),它是對(duì)內(nèi)部publicSetName的引用,而myRevealingModule.getName()的引用是對(duì)內(nèi)部publicGetName方法。例如:

myRevealingModule.setName("Mark");
// prints Name: Mark
myRevealingModule.getName();
對(duì)比普通模塊模式,揭示模塊模式的優(yōu)點(diǎn)如下:

通過(guò)修改return語(yǔ)句中的一行代碼,我們可以將成員從public更改為private,反之亦然。

返回的對(duì)象里不包含函數(shù)定義,所有右側(cè)表達(dá)式都在IIFE中定義了,代碼清晰易讀。

ES6模塊

在es6之前,js沒有模塊,所以開發(fā)者不得不第三方庫(kù)或者模塊模式來(lái)實(shí)現(xiàn)模塊。但在es6,js有了自己模塊實(shí)現(xiàn)。

ES6的模塊用文件來(lái)存儲(chǔ)。每個(gè)文件只能有一個(gè)模塊。默認(rèn)情況下,模塊內(nèi)的所有內(nèi)容都是私有的。開發(fā)者可以使用export關(guān)鍵字公開函數(shù)、變量和類。模塊內(nèi)的代碼始終以嚴(yán)格模式運(yùn)行。

輸出模塊

有兩種方式輸出函數(shù)和變量聲明:

在函數(shù)和變量的前面使用export關(guān)鍵字。例如:

// utils.js
export const greeting = "Hello World";
export function sum(num1, num2) {
console.log("Sum:", num1, num2);
return num1 + num2;
}
export function subtract(num1, num2) {
console.log("Subtract:", num1, num2);
return num1 - num2;
}
// This is a private function
function privateLog() {
console.log("Private Function");
}

在代碼的末尾加上export關(guān)鍵字,導(dǎo)出我們要公開的函數(shù)和變量:

// utils.js
function multiply(num1, num2) {
console.log("Multiply:", num1, num2);
return num1 * num2;
}
function divide(num1, num2) {
console.log("Divide:", num1, num2);
return num1 / num2;
}
// This is a private function
function privateLog() {
console.log("Private Function");
}
export {multiply, divide};

導(dǎo)入模塊

跟導(dǎo)出模塊差不多,也有兩種方法導(dǎo)入模塊:

導(dǎo)入特定的方法

// main.js
// importing multiple items
import { sum, multiply } from "./utils.js";
console.log(sum(3, 7));
console.log(multiply(3, 7));

導(dǎo)入所有

// main.js
// importing all of module
import * as utils from "./utils.js";
console.log(utils.sum(3, 7));
console.log(utils.multiply(3, 7));

導(dǎo)入和輸出的別名

如果要避免命名沖突,可以在導(dǎo)出和導(dǎo)入期間更改導(dǎo)出的名稱。例如:

重命名導(dǎo)出的方法

// utils.js
function sum(num1, num2) {
  console.log("Sum:", num1, num2);
  return num1 + num2;
}
function multiply(num1, num2) {
  console.log("Multiply:", num1, num2);
  return num1 * num2;
}
export {sum as add, multiply};

重命名導(dǎo)入的方法

// main.js
import { add, multiply as mult } from "./utils.js";
console.log(add(3, 7));
console.log(mult(3, 7));

單例模式

單例指的是只能實(shí)例化一次的對(duì)象。如果不存在,則單例模式會(huì)創(chuàng)建類的新實(shí)例。 如果存在實(shí)例,則它只返回對(duì)該對(duì)象的引用。 對(duì)構(gòu)造函數(shù)的任何重復(fù)調(diào)用總是會(huì)獲取相同的對(duì)象。

js支持單例模式,它有關(guān)于單例模式的實(shí)現(xiàn)。在js我們不應(yīng)該叫單例,應(yīng)該叫對(duì)象字面量。例如:

const user = {
  name: "Peter",
  age: 25,
  job: "Teacher",
  greet: function() {
    console.log("Hello!");
  }
};

因?yàn)樵趈s中,每個(gè)對(duì)象占用一個(gè)唯一的內(nèi)存位置,當(dāng)我們調(diào)用用戶對(duì)象時(shí),實(shí)際上返回的是該對(duì)象的引用。

如果我們嘗試復(fù)制user對(duì)象到另一個(gè)變量,并且修改其中的值。例如:

const user1 = user;
user1.name = "Mark";

我們會(huì)看到兩個(gè)對(duì)象都被修改,因?yàn)閖s中的對(duì)象是引用而不是值傳遞。所以內(nèi)存中只有一個(gè)對(duì)象。例如:

// prints "Mark"
console.log(user.name);
// prints "Mark"
console.log(user1.name);
// prints true
console.log(user === user1);

可以用構(gòu)造函數(shù)實(shí)現(xiàn)單例模式。例如:

let instance = null;
function User() {
  if(instance) {
    return instance;
  }
  instance = this;
  this.name = "Peter";
  this.age = 25;
  
  return instance;
}
const user1 = new User();
const user2 = new User();
// prints true
console.log(user1 === user2); 

當(dāng)這個(gè)構(gòu)造函數(shù)被調(diào)用,它會(huì)檢查instance是否存在。如果對(duì)象不存在,它會(huì)分配值給instance變量。如果存在,返回已存在的對(duì)象。

也可以使用模塊模式實(shí)現(xiàn)單例。例如:

const singleton = (function() {
  let instance;
  
  function init() {
    return {
      name: "Peter",
      age: 24,
    };
  }
  return {
    getInstance: function() {
      if(!instance) {
        instance = init();
      }
      
      return instance;
    }
  }
})();
const instanceA = singleton.getInstance();
const instanceB = singleton.getInstance();
// prints true
console.log(instanceA === instanceB);

在上面的代碼中,我們用singleton.getInstance方法創(chuàng)建了新的instance實(shí)例。如果實(shí)例已存在,則此方法返回已存在實(shí)例,如果實(shí)例不存在,則通過(guò)調(diào)用init()函數(shù)創(chuàng)建新實(shí)例。

工廠模式

工廠模式使用工廠方法創(chuàng)建對(duì)象,而不指定所創(chuàng)建對(duì)象的確切類或構(gòu)造函數(shù)。

工廠模式用于創(chuàng)建對(duì)象,不暴露實(shí)例化邏輯。當(dāng)我們需要根據(jù)特定條件生成不同的對(duì)象時(shí),可以使用此模式。例如:

class Car{
  constructor(options) {
    this.doors = options.doors || 4;
    this.state = options.state || "brand new";
    this.color = options.color || "white";
  }
}
class Truck {
  constructor(options) {
    this.doors = options.doors || 4;
    this.state = options.state || "used";
    this.color = options.color || "black";
  }
}
class VehicleFactory {
  createVehicle(options) {
    if(options.vehicleType === "car") {
      return new Car(options);
    } else if(options.vehicleType === "truck") {
      return new Truck(options);
      }
  }
}

我創(chuàng)建了car和truck類(帶有一些默認(rèn)值),用于創(chuàng)建新的汽車和卡車對(duì)象。然后我定義了VehicleFactory類,用于根據(jù)對(duì)象中收到的vehicleType屬性創(chuàng)建并返回一個(gè)新對(duì)象。

const factory = new VehicleFactory();
const car = factory.createVehicle({
  vehicleType: "car",
  doors: 4,
  color: "silver",
  state: "Brand New"
});
const truck= factory.createVehicle({
  vehicleType: "truck",
  doors: 2,
  color: "white",
  state: "used"
});
// Prints Car {doors: 4, state: "Brand New", color: "silver"}
console.log(car);
// Prints Truck {doors: 2, state: "used", color: "white"}
console.log(truck);

我是實(shí)例化了VehicleFactory類,之后我們調(diào)用factory.createVehicle方法創(chuàng)建car和truck對(duì)象,并且傳遞vehicleType屬性值為car或truck的options對(duì)象。

裝飾器模式

裝飾器模式用于擴(kuò)展對(duì)象的功能,而無(wú)需修改現(xiàn)有的類或構(gòu)造函數(shù)。此模式可用于向?qū)ο筇砑有鹿δ?,無(wú)需修改它們的基礎(chǔ)代碼。

一個(gè)簡(jiǎn)單的例子:

function Car(name) {
  this.name = name;
  // Default values
  this.color = "White";
}
// Creating a new Object to decorate
const tesla= new Car("Tesla Model 3");
// Decorating the object with new functionality
tesla.setColor = function(color) {
  this.color = color;
}
tesla.setPrice = function(price) {
  this.price = price;
}
tesla.setColor("black");
tesla.setPrice(49000);
// prints black
console.log(tesla.color);

這種模式更實(shí)際的例子是:

比方說(shuō),汽車的成本取決于它的功能數(shù)量。 如果沒有裝飾器模式,我們必須為不同的功能組合創(chuàng)建不同的類,每個(gè)類都有一個(gè)成本方法來(lái)計(jì)算成本。例如:

class Car() {
}
class CarWithAC() {
}
class CarWithAutoTransmission {
}
class CarWithPowerLocks {
}
class CarWithACandPowerLocks {
}

但有了裝飾器模式,我們可以基于car類創(chuàng)建對(duì)象,并且使用裝飾器函數(shù)添加不同的方法。例如:

class Car {
  constructor() {
  // Default Cost
  this.cost = function() {
  return 20000;
  }
}
}
// Decorator function
function carWithAC(car) {
  car.hasAC = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}
// Decorator function
function carWithAutoTransmission(car) {
  car.hasAutoTransmission = true;
   const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 2000;
  }
}
// Decorator function
function carWithPowerLocks(car) {
  car.hasPowerLocks = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}

首先,我們創(chuàng)建了用于創(chuàng)建car對(duì)象的基類Car。然后,我們?yōu)橐砑拥狡渖系囊貏?chuàng)建裝飾器,并將Car對(duì)象作為參數(shù)傳遞。 然后我們覆蓋該對(duì)象的cost函數(shù),該函數(shù)返回汽車的更新成本,并向該對(duì)象添加新屬性以指示添加了哪個(gè)特征。

為了添加新功能,我們可以這樣做:

const car = new Car();
console.log(car.cost());
carWithAC(car);
carWithAutoTransmission(car);
carWithPowerLocks(car);

最后,我們這樣子計(jì)算成本:

// Calculating total cost of the car
console.log(car.cost());
結(jié)論

我們已經(jīng)了解部分設(shè)計(jì)模式在js中的實(shí)現(xiàn),但是還有部分在本文沒有涉及。

雖然了解審設(shè)計(jì)模式很重要,但是不要過(guò)度使用它們。在使用某個(gè)設(shè)計(jì)模式之前,應(yīng)該考慮是否能解決你的痛點(diǎn)。要了解模式是否適合你,你應(yīng)該研究設(shè)計(jì)模式以及該設(shè)計(jì)模式的應(yīng)用。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98808.html

相關(guān)文章

  • PHPer書單

    摘要:想提升自己,還得多看書多看書多看書下面是我收集到的一些程序員應(yīng)該看得書單及在線教程,自己也沒有全部看完。共勉吧當(dāng)然,如果你有好的書想分享給大家的或者覺得書單不合理,可以去通過(guò)進(jìn)行提交。講師溫銘,軟件基金會(huì)主席,最佳實(shí)踐作者。 想提升自己,還得多看書!多看書!多看書!下面是我收集到的一些PHP程序員應(yīng)該看得書單及在線教程,自己也沒有全部看完。共勉吧!當(dāng)然,如果你有好的書想分享給大家的或者...

    jimhs 評(píng)論0 收藏0
  • 那些年,我的前端/Java后端書單

    摘要:全文為這些年,我曾閱讀深入理解過(guò)或正在閱讀學(xué)習(xí)即將閱讀的一些優(yōu)秀經(jīng)典前端后端書籍。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 全文為這些年,我曾閱讀、深入理解過(guò)(或正在閱讀學(xué)習(xí)、即將閱讀)的一些優(yōu)秀經(jīng)典前端/Java后端書籍。全文為純?cè)瓌?chuàng),且將持續(xù)更新,未經(jīng)許可,不得進(jìn)行轉(zhuǎn)載。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 基礎(chǔ) 基礎(chǔ)書籍 進(jìn)階 進(jìn)階階段,深入學(xué)習(xí)的書...

    fxp 評(píng)論0 收藏0
  • 那些年,我的前端/Java后端書單

    摘要:全文為這些年,我曾閱讀深入理解過(guò)或正在閱讀學(xué)習(xí)即將閱讀的一些優(yōu)秀經(jīng)典前端后端書籍。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 全文為這些年,我曾閱讀、深入理解過(guò)(或正在閱讀學(xué)習(xí)、即將閱讀)的一些優(yōu)秀經(jīng)典前端/Java后端書籍。全文為純?cè)瓌?chuàng),且將持續(xù)更新,未經(jīng)許可,不得進(jìn)行轉(zhuǎn)載。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 基礎(chǔ) 基礎(chǔ)書籍 進(jìn)階 進(jìn)階階段,深入學(xué)習(xí)的書...

    Tecode 評(píng)論0 收藏0
  • 那些年,我的前端/Java后端書單

    摘要:全文為這些年,我曾閱讀深入理解過(guò)或正在閱讀學(xué)習(xí)即將閱讀的一些優(yōu)秀經(jīng)典前端后端書籍。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 全文為這些年,我曾閱讀、深入理解過(guò)(或正在閱讀學(xué)習(xí)、即將閱讀)的一些優(yōu)秀經(jīng)典前端/Java后端書籍。全文為純?cè)瓌?chuàng),且將持續(xù)更新,未經(jīng)許可,不得進(jìn)行轉(zhuǎn)載。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 基礎(chǔ) 基礎(chǔ)書籍 進(jìn)階 進(jìn)階階段,深入學(xué)習(xí)的書...

    VPointer 評(píng)論0 收藏0
  • 那些年,我的前端/Java后端書單

    摘要:全文為這些年,我曾閱讀深入理解過(guò)或正在閱讀學(xué)習(xí)即將閱讀的一些優(yōu)秀經(jīng)典前端后端書籍。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 全文為這些年,我曾閱讀、深入理解過(guò)(或正在閱讀學(xué)習(xí)、即將閱讀)的一些優(yōu)秀經(jīng)典前端/Java后端書籍。全文為純?cè)瓌?chuàng),且將持續(xù)更新,未經(jīng)許可,不得進(jìn)行轉(zhuǎn)載。當(dāng)然,如果您喜歡這篇文章,可以動(dòng)手點(diǎn)點(diǎn)贊或者收藏。 基礎(chǔ) 基礎(chǔ)書籍 進(jìn)階 進(jìn)階階段,深入學(xué)習(xí)的書...

    idealcn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<