vue運(yùn)用的設(shè)計(jì)模式:1、單例模式,確保一個(gè)類只有一個(gè)實(shí)例對(duì)象,并提供一個(gè)全局訪問點(diǎn)供其訪問。2、工廠模式,是用來創(chuàng)建對(duì)象的一種模式,不必暴露構(gòu)造函數(shù)的具體邏輯,而是將邏輯封裝在一個(gè)個(gè)函數(shù)之中。3、裝飾器模式,允許向現(xiàn)有的函數(shù)添加新的功能,同時(shí)不改變其結(jié)構(gòu)。4、策略模式,就是定義一系列的算法,把他們一個(gè)個(gè)封裝起來,并且使他們可以相互替換。5、發(fā)布訂閱者模式。
本教程操作環(huán)境:windows7系統(tǒng)、vue3版,DELL G3電腦。
什么是設(shè)計(jì)模式:
設(shè)計(jì)模式的原則是找出程序中的變化,并將變化封裝起來,實(shí)現(xiàn)高效的可復(fù)用性。核心在于意圖,而不在結(jié)構(gòu)。通過設(shè)計(jì)模式可以幫助我們?cè)鰪?qiáng)代碼的可重用性、可擴(kuò)充性、 可維護(hù)性、靈活性。我們使用設(shè)計(jì)模式的最終目的是為了實(shí)現(xiàn)代碼的高類聚和低耦合。你是否思考過這樣的一個(gè)問題,如何讓代碼寫的更有健壯性,其實(shí)核心在于把握變與不變。確保變的部分更加靈活,不變的地方更加穩(wěn)定,而使用設(shè)計(jì)模式可以讓我們達(dá)到這樣的目的。
下面來總結(jié)一下vue項(xiàng)目中或者說工作中常用的設(shè)計(jì)模式。
單例模式
單例模式:確保一個(gè)類只有一個(gè)實(shí)例對(duì)象,并提供一個(gè)全局訪問點(diǎn)供其訪問。
優(yōu)點(diǎn):適用于單一對(duì)象,只生成一個(gè)對(duì)象實(shí)例,避免頻繁創(chuàng)建和銷毀實(shí)例,減少內(nèi)存占用。
缺點(diǎn):不適用動(dòng)態(tài)擴(kuò)展對(duì)象。
場(chǎng)景:登錄浮窗、Vue中的axios實(shí)例(我們對(duì)axios進(jìn)行請(qǐng)求攔截和響應(yīng)攔截,多次調(diào)用封裝好的axios但是僅設(shè)置一次,封裝好的axios導(dǎo)出就是一個(gè)單例)、全局態(tài)管理 store、線程池、全局緩存
function Person (name, age) { this.name = name this.age = age this.info = function () { console.log(`我的名字叫${this.name}, 我今年${this.age}了`) } } Person.getInstance = function (name, age) { if (!this.instance) { this.instance = new Person(name, age) } console.log(this.instance) return this.instance } let b1 = Person.getInstance('單例1', 18) let b2 = Person.getInstance('單例2', 18) b1.info() b2.info()
工廠模式
工廠模式:工廠模式是用來創(chuàng)建對(duì)象最常見的一種設(shè)計(jì)模式。不必暴露構(gòu)造函數(shù)的具體邏輯,而是將邏輯封裝在一個(gè)個(gè)函數(shù)之中,那么這個(gè)構(gòu)造函數(shù)就可以被看做工廠。
場(chǎng)景: 有構(gòu)造函數(shù)的地方,寫了大量的構(gòu)造函數(shù)代碼,調(diào)用了大量的new操作符。
優(yōu)點(diǎn):通過工廠模式,我們可以快速創(chuàng)建大量相似對(duì)象,沒有重復(fù)代碼。
缺點(diǎn):工廠模式創(chuàng)建的對(duì)象屬于Object,無法區(qū)分對(duì)象類型,這也是工廠模式?jīng)]有廣泛使用的原因。
function Factory (name, age) { this.name = name; this.age = age; // 或者 // let obj = {} // obj.name = name // obj.age = age // return obj } Factory.prototype.say = function () { console.log(`我的名字叫${this.name}, 我今年${this.age}了`) } let zs = new Factory('張三', 18); let ls = new Factory('李四', 20); zs.say() ls.say()
裝飾器模式
裝飾器模式(切面編程AOP): 在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)的添加職責(zé);若直接修改函數(shù)體,則違背了’開放封閉原則’,也違背了我們的’單一職責(zé)原則’;簡(jiǎn)單的說就是允許向現(xiàn)有的函數(shù)添加新的功能,同時(shí)不改變其結(jié)構(gòu)。
場(chǎng)景: vue中的表單驗(yàn)證與表單提交就運(yùn)用了這種模式,遵循封閉開放原則。
function before (fn, callback) { let _this = this; return function () { callback.apply(this, arguments) return fn.bind(this, arguments) } } function after (fn, callback) { let _this = this return function () { let res = fn.apply(this, arguments) callback.apply(this, arguments) return res } } // before和after是兩個(gè)高階函數(shù),讓我們一起回憶一下什么是高階函數(shù)? // 還知道call,apply,bind的區(qū)別嗎 let getName = function getName () { // 加入這是你同事寫的爛代碼,看不下去的那種,那么別動(dòng)他的代碼 console.log('這是getName函數(shù)') } before(getName, function () { // 這個(gè)就是你要寫的新邏輯 console.log('切入前代碼') })() after(getName, function () { // 這個(gè)也是你要寫的新邏輯 console.log('切入后代碼') })()
策略模式
策略模式: 就是定義一系列的算法,把他們一個(gè)個(gè)封裝起來,并且使他們可以相互替換。
let strategy = { 'A': function (bonus) { return bonus * 4 }, 'B': function (bonus) { return bonus * 3 } } function fn (level, bonus) { return strategy[level](bonus) } let result = fn('A', 4000) console.log(result, 'result') // 策略模式提供了開放-封閉原則,將算法或者方法封裝在一個(gè)類中,使它們易于切換,易于替換。 function func (a, b) { let f = function f() { return a + b } return f }
在vue表單驗(yàn)證時(shí)也可以運(yùn)用
// 這里可以將所有的表單驗(yàn)證正則函數(shù)寫在這里 export const loginUsername = (str) => { return /^[a-zA-Z0-9_]{3,20}$/.test(str); };
import * as validateForm from './validate'; export const gene = (key, msg) => { return (r, v, c) => { if (validateForm[key](v)) { c(); } else { c(new Error(msg)); } }; };
// 這樣看著是不是很清晰明了 import {gene} from '@/utils/formValidateGene'; rules: { account: [{ required: true, validator: gene('loginUsername', '請(qǐng)輸入合適的賬號(hào)'), trigger: ['blur', 'change'] }] }
發(fā)布訂閱者模式
發(fā)布訂閱者模式又叫觀察者模式,發(fā)布訂閱者模式一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得將得到通知;觀察者模式則是一種一對(duì)一的依賴關(guān)系。
- 手寫觀察者模式
class Observer { client = {} // 訂閱 listen (key, fn) { if (!this.client[key]) { this.client[key] = [] } this.client[key].push(fn) } // 發(fā)布 publish (key) { this.client[key].forEach(fn => { fn.apply(this, arguments) }) } } let observer = new Observer() observer.listen('華為', (model, brand) => { console.log(model, brand) }) observer.listen('蘋果', function (model, brand) { console.log(model, brand) }) observer.publish('華為', 'P50') observer.publish('蘋果', '14')
- 手寫響應(yīng)式
class EventEmitter { constructor () { this.client = {} } on (key, fn) { if (!this.client[key]) { this.client[key] = [] } this.client[key].push(fn) } trigger (key, ...args) { this.client[key].forEach(cb => cb(...args)) } } let event = new EventEmitter() event.on('hello', function(res) { console.log('hello', res) }) let data = { name: '測(cè)試' } Object.defineProperty(data, 'name', { get (val) { // console.log(val) }, set (newVal) { console.log(newVal) event.trigger('hello', newVal) } }) data.name = '正在測(cè)試'
【