結(jié)合ES6?編寫?JavaScript?設(shè)計(jì)模式中的結(jié)構(gòu)型模式
前言
本文將對(duì) 20 多種 JavaScript 設(shè)計(jì)模式進(jìn)行簡(jiǎn)單概述,然后結(jié)合 ES6 類的方式來(lái)編寫實(shí)例代碼展示其使用方式。
JavaScript 在現(xiàn)代前端中扮演重要的角色,相比過(guò)去能夠做的事情已經(jīng)不在一個(gè)級(jí)別上了。JavaScript 最大的特征是其靈活性,一般只要敢想敢寫,可以把程序?qū)懙煤芎?jiǎn)單,有可以寫得很復(fù)雜。其靈活性導(dǎo)致編寫 JavaScript 的時(shí)候能夠不斷的優(yōu)化,能夠不斷質(zhì)疑寫的質(zhì)量。而設(shè)計(jì)模式,是不分編程語(yǔ)言的,是軟件工程的內(nèi)容,JavaScript 強(qiáng)大的表現(xiàn)力賦予了開(kāi)發(fā)者運(yùn)用設(shè)計(jì)模式編寫代碼時(shí)創(chuàng)造性。
設(shè)計(jì)模式系列文章:
什么是設(shè)計(jì)模式?
設(shè)計(jì)模式是軟件設(shè)計(jì)中常見(jiàn)問(wèn)題的解決方案,這些模式很容易重復(fù)使用并且富有表現(xiàn)力。
在軟件工程中,設(shè)計(jì)模式(design pattern)是對(duì)軟件設(shè)計(jì)中普遍存在(反復(fù)出現(xiàn))的各種問(wèn)題,所提出的解決方案。它并不直接用來(lái)完成代碼的編寫,而是描述在各種不同情況下,要怎么解決問(wèn)題的一種方案。面向?qū)ο笤O(shè)計(jì)模式通常以類別或?qū)ο髞?lái)描述其中的關(guān)系和相互作用,但不涉及用來(lái)完成應(yīng)用程序的特定類別或?qū)ο蟆?mdash;— 維基百科
在 JavaScript 中使用設(shè)計(jì)模式主要有以下原因:
- 可維護(hù)性:設(shè)計(jì)模式有助于降低模塊間的耦合程度。
- 溝通:設(shè)計(jì)模式為處理不同類型的對(duì)象提供了一套通用的術(shù)語(yǔ)。
- 性能:對(duì)代碼起到優(yōu)化作用,提高程序的運(yùn)行速度。當(dāng)然不是所有的設(shè)計(jì)模式都能夠改善性能。
有三種模式:創(chuàng)建型模式,結(jié)構(gòu)型模式、行為型模式。
- 創(chuàng)建型模式:解決與創(chuàng)建對(duì)象相關(guān)的問(wèn)題。
- 結(jié)構(gòu)型模式:處理實(shí)體之間的關(guān)系,以及它們?nèi)绾喂餐M成一個(gè)更大的結(jié)構(gòu)。
- 行為型模式:處理對(duì)象如何相互通信和交互。
結(jié)構(gòu)型設(shè)計(jì)模式
結(jié)構(gòu)型設(shè)計(jì)模式涉及類和對(duì)象組合,使用繼承來(lái)組合接口。
在軟件工程中,結(jié)構(gòu)設(shè)計(jì)模式是通過(guò)識(shí)別實(shí)現(xiàn)實(shí)體之間關(guān)系的簡(jiǎn)單方法來(lái)簡(jiǎn)化設(shè)計(jì)的設(shè)計(jì)模式。
- 適配器模式
- 橋接模式
- 組合模式
- 裝飾者模式
- 門面模式
- 享元模式
- 代理模式
適配器模式
適配器模式允許具有不兼容接口的類通過(guò)將它們自己的接口封裝在現(xiàn)有類周圍來(lái)一起工作。適配器也稱為包裝器(wrapper),用來(lái)把不匹配的接口替換為一個(gè)可用于現(xiàn)有系統(tǒng)中的接口。
在軟件工程中,適配器模式是一種軟件設(shè)計(jì)模式,它允許將現(xiàn)有類的接口用作另一個(gè)接口。它通常用于使現(xiàn)有類在不修改其源代碼的情況下與其他類一起使用。
實(shí)例
實(shí)例將通過(guò)一個(gè)計(jì)算器的例子進(jìn)行改造。 Calculator1
是舊接口,Calculator2
是新接口。將構(gòu)建一個(gè)適配器,它將包裝新接口并使用其新方法為其提供結(jié)果。
class Calculator1 { constructor() { this.operations = function (value1, value2, operation) { const operationHandler = { add: () => value1 + value2, sub: () => value1 - value2, }; return ( typeof (operationHandler[operation] === "function") && operationHandler[operation]() ); }; } } class Calculator2 { constructor() { this.add = function (value1, value2) { return value1 + value2; }; this.sub = function (value1, value2) { return value1 - value2; }; } } // 使用適配器模式構(gòu)建類 class CalcAdapter { constructor() { const cal2 = new Calculator2(); this.operations = function (value1, value2, operation) { return ( typeof (cal2[operation] === "function") && cal2[operation](value1, value2) ); }; } } const adaptedCalc = new CalcAdapter(); console.log(adaptedCalc.operations(30, 25, "sub")); // 5
橋接模式
橋接模式將抽象與實(shí)現(xiàn)分開(kāi),以便兩者可以獨(dú)立變化。是一種既能把兩個(gè)對(duì)象連接在一起,又能避免二者間的強(qiáng)耦合的方法。
橋接模式是一種結(jié)構(gòu)化設(shè)計(jì)模式,它允許將一個(gè)大類或一組密切相關(guān)的類拆分為兩個(gè)獨(dú)立的層次結(jié)構(gòu):抽象和實(shí)現(xiàn),它們可以相互獨(dú)立地開(kāi)發(fā)。—— 維基百科
實(shí)例
將創(chuàng)建渲染器類來(lái)渲染多個(gè)形狀。
class VectorRenderer { renderCircle(radius) { console.log(`渲染一個(gè)半徑為 ${radius} 的圓`); } } class RasterRenderer { renderCircle(radius) { console.log(`繪制一個(gè)半徑為 ${radius} 的像素圓`); } } class Shape { constructor(renderer) { this.renderer = renderer; } } class Circle extends Shape { constructor(renderer, radius) { super(renderer); this.radius = radius; } draw() { this.renderer.renderCircle(this.radius); } resize(factor) { this.radius *= factor; } } const raster = new RasterRenderer(); const vector = new VectorRenderer(); const circle = new Circle(vector, 5); const rasterCircle = new Circle(raster, 5); circle.draw(); circle.resize(2); circle.draw(); rasterCircle.draw(); rasterCircle.resize(2); rasterCircle.draw();
組合模式
組合模式組合對(duì)象,以便可以將它們作為單個(gè)對(duì)象進(jìn)行操作,非常適合用于創(chuàng)建WEB上的動(dòng)態(tài)用戶界面。
組合模式描述了一組對(duì)象,這些對(duì)象的處理方式與相同類型對(duì)象的單個(gè)實(shí)例相同。—— 維基百科
實(shí)例
將使用工作示例:
class Employer { constructor(name, role) { this.name = name; this.role = role; } print() { const { name } = this; console.log(`姓名:${name}`); } } class EmplyerGroup { constructor(name, composite = []) { console.log(name); this.name = name; this.composite = composite; } print() { console.log(this.name); this.composite.forEach((emp) => { emp.print(); }); } } const ravi = new Employer("ravi", "developer"); const bhavy = new Employer("bhavy", "developer"); const groupDevelopers = new EmplyerGroup("Developer", [ravi, bhavy]); groupDevelopers.print();
裝飾者模式
裝飾者模式動(dòng)態(tài)地添加或覆蓋對(duì)象的行為,用于把對(duì)象透明的包裝到另一個(gè)種具有相同接口的對(duì)象中。
裝飾器模式是一種設(shè)計(jì)模式,它允許將行為動(dòng)態(tài)地添加到單個(gè)對(duì)象,而不會(huì)影響同一類中其他對(duì)象的行為。
實(shí)例
將以顏色和形狀為例,如果必須畫一個(gè)圓,將創(chuàng)建方法并畫一個(gè)圓。如果要畫一個(gè)紅色的圓圈,將行為被添加到一個(gè)對(duì)象中,裝飾器模式將幫助實(shí)現(xiàn)。
class Shape { constructor(color = "") { this.color = color; } } class Circle extends Shape { constructor(radius = 0) { super(); this.radius = radius; } resize(factor) { this.radius *= factor; } toString() { return `一個(gè)直徑為 ${this.radius} 的園`; } } class ColoredShape extends Shape { constructor(shape, color) { super(); this.shape = shape; this.color = color; } toString() { return `${this.shape.toString()},顏色為${this.color}`; } } const circle = new Circle(2); console.log(circle); // Circle { color: '', radius: 2 } const redCircle = new ColoredShape(circle, "紅色"); console.log(redCircle.toString()); // 一個(gè)直徑為 2 的園,顏色為紅色
門面模式
門面模式為復(fù)雜代碼提供了一個(gè)簡(jiǎn)化的接口,可以用來(lái)把現(xiàn)有接口轉(zhuǎn)換為一個(gè)更便于使用的接口。
門面模式是面向?qū)ο缶幊讨谐S玫囊环N軟件設(shè)計(jì)模式。與架構(gòu)中的外觀類似,外觀是一個(gè)對(duì)象,它充當(dāng)前端接口,掩蓋更復(fù)雜的底層或結(jié)構(gòu)代碼。 —— 維基百科
實(shí)例
舉一個(gè)客戶端與計(jì)算機(jī)交互的例子:
class CPU { freeze() { console.log("凍結(jié)…"); } jump() { console.log("跳過(guò)…"); } execute() { console.log("執(zhí)行…"); } } class Memory { load(position, data) { console.log("加載中…"); } } class HardDrive { read(lba, size) { console.log("讀取中…"); } } class ComputerFacade { constructor() { this.processor = new CPU(); this.ram = new Memory(); this.hd = new HardDrive(); } start() { this.processor.freeze(); this.ram.load("", this.hd.read("lba", "size")); this.processor.jump(""); this.processor.execute(); } } const computer = new ComputerFacade(); computer.start();
享元模式
享元模式降低了創(chuàng)建類似對(duì)象的內(nèi)存成本,是一種可以用于優(yōu)化目的的設(shè)計(jì)模式。最適合用于解決因創(chuàng)建大量類似對(duì)象而累及性能的問(wèn)題。
享元是一種通過(guò)與其他類似對(duì)象共享盡可能多的數(shù)據(jù)來(lái)最小化內(nèi)存使用的對(duì)象。—— 維基百科
實(shí)例
以用戶為例,讓有多個(gè)同名的用戶,可以通過(guò)存儲(chǔ)一個(gè)名稱來(lái)節(jié)省內(nèi)存,并將其引用給具有相同名稱的用戶。
class User { constructor(fullname) { this.fullname = fullname; } } class User2 { constructor(fullname) { const getOrAdd = (s) => { const idx = User2.strings.indexOf(s); if (idx !== -1) { return idx; } else { User2.strings.push(s); return User2.strings.length - 1; } }; this.names = fullname.split(" ").map(getOrAdd); } } User2.strings = []; const getRadmon = (max) => Math.floor(Math.random() * Math.floor(max)); const randomString = () => { const result = []; for (let x = 0; x < 10; ++x) { result.push(String.fromCharCode(65 + getRadmon(26))); } return result.join(""); };
現(xiàn)在將通過(guò)創(chuàng)建 10k 個(gè)用戶來(lái)進(jìn)行不使用享元模式和使用享元模式的占用字符大小來(lái)類比內(nèi)存大小。
const users = []; const users2 = []; const firstnames = []; const lastnames = []; for (let i = 0; i < 100; ++i) { firstnames.push(randomString()); lastnames.push(randomString()); } for (const first of firstnames) { for (const last of lastnames) { users.push(new User(`${first} ${last}`)); users2.push(new User2(`${first} ${last}`)); } } console.log(`10k用戶占用了大約 ${JSON.stringify(users).length} 字符`); // 10k用戶占用了大約 370001 字符 const user2length = [users2, User2.strings] .map((x) => JSON.stringify(x).length) .reduce((x, y) => x + y); console.log(`10k用戶在享元模式占用約 ${user2length} 字符`); // 10k用戶在享元模式占用約 191602 字符
代理模式
通過(guò)使用代理,一個(gè)類可以代表另一個(gè)類的功能。更加詳細(xì)的介紹,可以參閱《JavaScript 設(shè)計(jì)模式之代理模式》
代理模式是一種軟件設(shè)計(jì)模式。代理,在其最一般的形式中,是一個(gè)作為與其他事物的接口的類。—— 維基百科
實(shí)例
以價(jià)值代理作為實(shí)例。
class Percentage { constructor(percent) { this.percent = percent; } toString() { return `${this.percent}%`; } valueOf() { return this.percent / 100; } } const fivePercent = new Percentage(5); console.log(fivePercent.toString()); // 5% console.log(`5% 的50倍是${50 * fivePercent}`); // 5% 的50倍是2.5
到此這篇關(guān)于結(jié)合ES6 編寫 JavaScript 設(shè)計(jì)模式中的結(jié)構(gòu)型模式的文章就介紹到這了,更多相關(guān)JS 結(jié)構(gòu)型模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js HTML5 Ajax實(shí)現(xiàn)文件上傳進(jìn)度條功能
這篇文章主要介紹了javascript實(shí)現(xiàn)文件上傳進(jìn)度條功能的相關(guān)資料啊,感興趣的朋友可以參考一下2016-02-02JS實(shí)現(xiàn)三級(jí)折疊菜單特效,其它級(jí)可自動(dòng)收縮
這篇文章主要介紹了JS實(shí)現(xiàn)三級(jí)折疊菜單特效,其它級(jí)可自動(dòng)收縮,需要的朋友可以參考下2015-08-08js寫一個(gè)字符串轉(zhuǎn)成駝峰的實(shí)例
寫一個(gè)字符串轉(zhuǎn)成駝峰的方法,使用js代碼實(shí)現(xiàn),具體如下,感興趣的朋友可以了解下哈2013-06-06js實(shí)現(xiàn)無(wú)縫滾動(dòng)圖(可控制當(dāng)前滾動(dòng)的方向)
本文主要分享了js實(shí)現(xiàn)無(wú)縫滾動(dòng)圖的示例代碼,這個(gè)版本可以控制左右滾動(dòng),鼠標(biāo)點(diǎn)擊對(duì)應(yīng)的廣告會(huì)自動(dòng)滑動(dòng)把廣告完全展示出來(lái),當(dāng)鼠標(biāo)離開(kāi),接著繼續(xù)滾動(dòng)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02微信小程序+mqtt,esp8266溫濕度讀取的實(shí)現(xiàn)方法
這篇文章主要介紹了微信小程序+mqtt,esp8266溫濕度讀取的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04基于JavaScript實(shí)現(xiàn)文字超出部分隱藏
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)文字超出部分隱藏 的相關(guān)資料,需要的朋友可以參考下2016-02-02