日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Javascript设计模式

發布時間:2023/12/15 java 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Javascript设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

設計原則(SOLID)

單一職責模式(S)

  • 一個程序只做好一件事
  • 如果功能過于復雜就拆分開,每個部分保持獨立

里式替換原則(L)

  • 子類能覆蓋父類
  • 父類能出現的地方子類就能出現
  • JS中使用較少(弱類型&繼承使用較少)

開放封閉原則(O)

  • 對擴展開放對修改封閉
  • 增加需求時,擴展新代碼,而非修改已有代碼
  • 軟件設計的終極目標

接口隔離原則(I)

  • 保持接口的單一獨立,避免出現"胖接口"
  • JS中沒有接口(typescript例外),使用較少
  • 類似于單一職責所在,這里更關注接口

依賴倒置原則(D)

  • 面向接口編程,依賴于抽象而不依賴于具體
  • 使用方只關注接口而不關注具體類的實現
  • JS中使用較少(沒有接口&弱類型)

設計模式

工廠模式

  • 將new操作單獨封裝
  • 遇到new時,就要考慮是否該使用工廠模式了

示例

你去購買漢堡,直接點餐、取餐,不會自己親手做
商店要“封裝”做漢堡的工作,做好直接給買者

UML類圖:

代碼示例:

class Product {constructor(name) {this.name = name;}init() {console.log('init')}fn1() {console.log('fn1')}fn2() {console.log('fn2')} }class Creator {create(name) {return new Product(name)} }let create = new Creator(); let p = create.create('p') p.init() p.fn1() p.fn2()

應用場景

  • jQuery:

$('div')和new $('div')有何區別?

  • 第一:書寫麻煩,jQuery的鏈式操作將成為噩夢
  • 第二:一旦jQuery名字變化,將是災難性的
//仿jQuery代碼 class jQuery {constructor(selector) {let slice = Array.prototype.slice;let dom = slice.call(document.querySelectorAll(selector))let len = dom ? dom.length : 0for (let i = 0; i < len; i++) {this[i] = dom[i]}this.length = lenthis.selector = selector || ''}append() {console.log('append');}addClass() {console.log('addClass')}}window.$ = function(selector) {return new jQuery(selector); }var $p = $('p') console.log($p) console.log($p.addClass)
  • React.crateElement:
var profile = <div><img src="avater.png" className="profile"/><h3>{[user.firstName,user.lastName].join('')}</h3></div>; 編譯完之后: var profile = React.createElement("div",null,React.createElement("img",{src:"avater.png",className:"profile"}),React.createElement("h3",null,[user.firstName,user.lastName].join(" ")) ); //源碼實現 class vnode(tag, attrs, children) {//...省略內部代碼... }React.createElement = function(tag,attrs,children){return new vnode(tag,attrs,children) }
  • Vue的異步組件:
Vue.component('async-example', funciton(resolve, reject) {setTimeout(function() => {resolve({template: '<div>I am async!</div>'})}, 1000); })

設計原則驗證:

  • 構造函數和創建者分離
  • 符合開放封閉原則

單例模式

  • 系統中被唯一使用
  • 一個類中只有一個實例

?

實例:

登錄框、購物車

傳統UML圖

說明
  • 單例模式需要用到java的特性(private)
  • ES6中沒有(typescript除外)
  • 只能用java代碼來演示UML圖的內容(最后用js變相實現)

代碼演示

java版的單例模式演示 public class SingleObject{//注意:私有化構造函數,外部不能new,只能內部new!!!!private SingleObject(){}//唯一被new出來的對象private SingleObject getInstance(){if(instance == null){//只new一次instance = new SingleObject();}return instance;}//對象方法public void login(username,password){System.out.println("login...")}}public class SingletonPatternDemo{public static void main(String[] args){//不合法的構造函數//編譯時報錯:構造函數 SingleObject()是不可見的!!!//SingleObject object = new SingleObject();//獲取唯一可用的對象SingleObject object = SingleObject.getInstance();} } Javascript版的單例模式演示 class SingleObject {login() {console.log('login...')} }//靜態方法 SingleObject.getInstance = (function() {let instancereturn function() {if (!instance) {instance = new SingleObject();}return instance;} })()var login = SingleObject.getInstance().login(); javascript的單例模式缺點:

如果強制new也不會報錯:

var loginnew = new SingleObject(); loginnew.login() 測試 //注意這里只能用靜態函數getInstance,不能new SingleObject()!!! let obj1 = SingleObject.getInstance() obj1.login() let obj2 = SingleObject.getInstance() obj2.login() console.log(obj1 === obj2); //兩者必須完全相同 只有通過模塊化完整實現

場景

  • jQuery 只有一個'$'
if(window.jQuery != null){return window.jQuery }else{//初始化... } //引用多少次都只有一個'$'
  • vuex 和 redux中的store
  • 購物車、登錄框
class LoginForm {constructor() {this.state = 'hide'}show() {if (this.state === 'show') {alert('已經顯示了');return}this.state = 'show'console.log('登錄框顯示成功')}hide() {if (this.state === 'hide') {alert('已經隱藏')return}this.state = 'hide'console.log('登錄框隱藏成功')} } LoginForm.getInstance = (function() {let instancereturn function() {if (!instance) {instance = new LoginForm()}return instance} })()let login1 = LoginForm.getInstance() login1.show()let login2 = LoginForm.getInstance() //lgoin2.show() //登錄框已經顯示 login2.hide()console.log(login1 === login2)

設計原則驗證

  • 符合單一職責原則,只實例化唯一的對象
  • 沒法具體開放封閉原則,但是絕對不違反開放封閉原則

適配器模式

  • 舊接口格式和使用者不兼容
  • 中間加一個適配轉換接口

示例

macbookpro適配器轉換
電源插座國家不統一需要轉換頭

UML圖

演示

class Adaptee {specificRequest() {return '德國標準插頭'} }class Target {constructor() {this.Adaptee = new Adaptee()}request() {let info = this.Adaptee.specificRequest()return `${info} - 轉換器 - 中國標準插頭`} }let target = new Target() let res = target.request() console.log(res)

應用場景

  • 封裝舊接口
//自己封裝的ajax,使用方式如下: ajax({url:'/getDate',type:'Post',dataType:'json',data:{id:123} }) .done(function(){}) //但因為歷史原因,代碼中全都是: //$.ajax({...}) 解決辦法: //做一層適配器 var $ = {ajax:function(options){return ajax(options)} }
  • vue computed
<div id="example"><p>Original message:"{{message}}"</p><p>Computed reversed message:"{{reversedMessage}}"</p> </div>var vm = new Vue({el:"#example",data:{mesage:'Hello'},computed:{//計算屬性的getterreversedMessage:function(){//'this'指向vm實例return this.message.split('').reverse().join('')}} })

設計原則驗證

  • 將舊接口和使用者進行分離
  • 符合開放封閉原則

裝飾器模式

  • 為對象添加新功能
  • 不改變其原有的結構和功能

示例:

手機殼

UML類圖

代碼演示

class Circle {draw() {console.log('畫一個圓形')} }class Decorator {constructor(circle) {this.circle = circle}draw() {this.circle.draw()this.setRedBorder(circle)}setRedBorder(circle) {console.log('設置紅色邊框')} }let circle = new Circle(); circle.draw()let decorator = new Decorator(circle) decorator.draw()

使用場景

  • ES7裝飾器
@testDec class Demo {//... }function testDec(target) {target.isDec = true; } alert(Demo.isDec); 裝飾器原理 @decorator class A {}//等同于 class A{} A = decorator(A)||A; 可以加參數 function testDec(isDec){return function(target){target.isDec = isDec;} }@testDec(true)class Demo{//.... } alert(Demo.isDec) //true function mixin(...list) {return function(target) {Object.assign(target.prototype, ...list)} }const Foo = {foo() { alert('foo') } }@mixin(Foo) class myClass() {}let obj = new myClass(); obj.foo() //'foo' 裝飾方法-例1 class Person {constructor() {this.first = 'A'this.last = 'B'}//裝飾方法@readonlyname() {return `${this.first} ${this.last}`} }var p = new Person() console.log(p.name()) //p.name=function(){} //這里會報錯,因為name是只讀屬性function readonly(target, name, descriptor) {//descriptor 屬性描述對象(Object.defineProperty中會用到),原來的值如下//{// value:specifiedFunction,// enumerable:false,// configurable:true,// writable:true //}descriptor.writable = false;return descriptor; } 裝飾方法-例2 class Math{//裝飾方法@logadd(a,b){return a + b;} }const math = new Math(); const result = math.add(2,4); //執行add時,會自動打印日志,因為有@log裝飾器 console.log('result',result)function log(target, name, descriptor) {var oldvalue = descriptor.value;descriptor.value = function() {console.log(`calling ${name} with`, arguments);return oldvalue.apply(this, arguments)}return descriptor; }
  • core-decorators
  • 第三方開源lib
  • 提供常用的裝飾器
//首先安裝npm i core-decorators --save//開始編碼 import { readonly } from 'core-decorators'class Person {@readonlyname() {return 'zhang'} }let p = new Person() alert(p.name())//p.name = function(){/*...*/} 此處會報錯 import { deprecate } from 'core-decorators'class Person {@deprecatename() {return 'zhang'} }let p = new Person() alert(p.name())//this funciton will be removed in future Vue.version//也可以自己定義@deprecate("即將廢用")//也可以自己定義@deprecate("即將廢用",{url:"www.imooc.com"})

設計原則驗證

  • 將現有對象和裝飾器進行分離,兩者獨立存在
  • 符合開放封閉原則

代理模式

  • 使用者無權訪問目標對象
  • 中間加代理,通過代理做授權和控制

示例:

  • 科學上網
  • 明星經紀人

UML

代碼演示

class RealImg {constructor(fileName) {this.fileName = fileName;this.loadFromDisk() //初始化即從硬盤中加載,模擬}display() {console.log('display...' + this.fileName)}loadFromDisk() {console.log('loading...' + this.fileName)} }class ProxyImg {constructor(fileName) {this.realImg = new RealImg(fileName)}display() {this.realImg.display()} }let proxyImg = new ProxyImg('1.png') proxyImg.display()

場景

  • 網頁事件代理
var div1 = document.getElementById('div1')div1.addEventListener('click', funtion(e) {console.log(e)var target = e.targetif (target.nodeName === "A") {alert(target.innerHtml)} })
  • jQuery $.proxy
$('#div1').click(function() {//this符合期望$(this).addClass('red') }) $('#div1').click(function() {setTimeout(function() {//this不符合期望$(this).addClass('red')}, 1000); }) //可以用如下方式解決 $('#div1').click(function() {var _this = thissetTimeout(funciton() {//_this符合期望$(_this).addClass('red')}, 1000) }) 或者用$.proxy //但推薦用$.proxy解決,這樣就少定義一個變量 $('#div1').click(function() {setTimeout($.proxy(function() {//this符合期望$(this).addClass('red')},this), 1000) })
  • ES6 Proxy
//明星 let star = {name: "zhangxx",age: 25,phone: '13910733521', }//經紀人 let agent = new Proxy(star, {get: function(target, key) {if (key === 'phone') {//返回經紀人自己的手機號return '13838383838'}if (key === "price") {//明星不報價,經紀人報價return 120000}return target[key]},set: function(target, key, val) {if (key === 'customPrice') {if (val < 100000) {throw new Error("價格太低")} else {target[key] = valreturn true}}} })console.log(agent.name) console.log(agent.phone) console.log(agent.age) console.log(agent.price)agent.customPrice = 150000; console.log('agent.customPrice', agent.customPrice)

設計原則驗證

  • 代理類和目標類分離,隔離開目標類和使用者
  • 符合開放封閉原則

代理模式VS適配器模式

  • 適配器模式:提供一個不同的接口(如不同版本的插頭,無法使用)
  • 代理模式:提供一模一樣的接口(無權使用)

代理模式VS裝飾器模式

  • 裝飾器模式:擴展功能,原有功能不變且可直接使用
  • 代理模式:直接針對(顯示)原有功能,但是經過限制或者閹割之后的

外觀模式

  • 為子系統中的一組接口提供了一個高層接口
  • 使用者使用這個高層接口

示例:

去醫院看病,接待員去掛號、門診、劃價、取藥

UML類圖

代碼演示

function bindEvent(elem,type,selector,fn){if(fn == null){fn = selectorselector = null} }//調用 bindEvent(elem,'click','#div1',fn) bindEvent(elem,'click',fn)

設計原則驗證

  • 不符合單一職責原則和開放封閉原則,因此謹慎使用,不可濫用

觀察者模式

  • 發布&訂閱
  • 一對多(N)

示例

  • 點咖啡,點好之后坐等被叫

UML類圖


前端設計最重要的一種模式

代碼演示

//保存狀態,狀態變化之后觸發所有觀察者 class Subject {constructor() {this.state = 0this.observers = []}getState() {return this.state}setState(state) {this.state = statethis.notifyAllObervers()}notifyAllObervers() {this.observers.forEach(observer => {observer.update()})}attach(observer) {this.observers.push(observer)} }//觀察者 class Observer {constructor(name, subject) {this.name = namethis.subject = subjectthis.subject.attach(this)}update() {console.log(`${this.name} update,state:${this.subject.getState()}`)} }let subject = new Subject(); let obs1 = new Observer('o1', subject); let obs2 = new Observer('o2', subject); let obs3 = new Observer('o3', subject);subject.setState(1) subject.setState(2)

應用場景

  • 網頁事件綁定

所有的事件監聽用的都是觀察者模式

<button id="btn1">btn</button><script>$('#btn1').click(function () {console.log(1)})$('#btn1').click(function () {console.log(2)})$('#btn1').click(function () {console.log(2)}) </script>
  • Promise
function loadImg(src) {var promise = new Promise(function(resolve, reject) {var img = document.createElement('img')img.onload = function() {resolve(img)}img.onerror = function() {reject('圖片加載失敗')}img.src = src})return promise }var src = "https://www.xxx.com/img/dafdafdfdafdsafd.png" var result = loadImg() result.then(function(img){console.log('width',img.width) }).then(function(img){console.log('width',img.height) })
  • jQuery callbacks
var callbacks = $.Callbacks() //注意大小寫 callbacks.add(function() {console.log('fn1', info) }) callbacks.add(function() {console.log('fn2', info) }) callbacks.add(function() {console.log('fn3', info) }) callbacks.fire('gogoogogo') callbacks.fire('fire')
  • nodejs自定義事件
cosnt EventEmitter = require('events').EventEmitter const emitter1 = new EventEmitter() emitter1.on('some', () => {//監聽some事件console.log('some events is occured 1') })emitter1.on('some', () => {//監聽some事件console.log('some events is occured 2')})//觸發some事件 emitter1.emit('some') const EventEmitter = require('events').EventEmitter//任何構造函數都可以繼承 EventEmitter的方法on emitclass Dog extends EventEmitter {constructor(name) {super()this.name = name} }var simon = new Dog('simon') simon.on('bark', function() {console.log(this.name, 'barked') }) setInterval(() => {simon.emit('bark') }, 500) //Stream 用到了自定義事件var fs = require('fs') var readStream = fs.createReadStream('./data/file1.txt') //讀取文件的streamvar length = 0 readStream.on('data', function(chunk) {length += chunk.toString().length })readStream.on('read', function() {console.log(length) }) //readline用到了自定義事件var readline = require('readline') var fs = require('fs')var rl = readline.createInterface({input: fs.createReadStream('./data/file1.txt') });var lineNum = 0 rl.on('line', function(line) {lineNum++ }) rl.on('close', function() {console.log('lineNum', lineNum) })
  • nodejs中:處理http請求;多進程通訊
function serverCallback(req, res) {var method = req.method.toLowerCase() //獲取請求方法if (method === 'get') {//省略3行,上文代碼示例中處理GET請求的代碼}if (method === 'post') {//接受post請求的內容var data = ''req.on('data', function() {//"一點一點"接收內容data += chunk.toString()})req.on('end', function() {//接收完畢,將內容輸出res.writeHead(200, { 'Content-type': 'text/html' })res.write(data)res.end()})} } //parent.js var cp = require('child_process') var n = cp.fork('./sub.js') n.on('message', function(m) {console.log('PARENT got message:' + m) }) n.send({ hello: 'workd' })//sub.js process.on('message', function(m) {console.log('CHILD got message:' + m) })process.send({ foo: 'bar' })
  • vue和React組件生命周期觸發
class login extends React.component {constructor(prop, context) {super(props, context)this.shouldComponentUpate = PureRenderMixin.shouldComponentUpate.bind(this);this.state = {checking: true}}render() {return ( <div><header title = "登錄" history = { this.props.history } ></header> </div >)}componentDidMount() {//判斷是否已經登錄this.doCheck()} }
  • vue watch
var vm = new Vue({el: "#demo",data: {firstName: 'Foo',lastName: 'Bar',fullName: 'Foo Bar'},watch: {firstName: function(val) {this.fullName = val + '' + this.lastName},lastName: function(val) {this.fullName = this.firstName + '' + val}} })

設計原則驗證

  • 主題和觀察者分離,不是主動觸發而是被動監聽,兩者解耦
  • 符合開放封閉原則

迭代器模式

  • 順序訪問一個集合
  • 使用者無需知道集合的內部結構(封裝)

示例

  • 沒有合適的示例,jQuery演示一下
<p>jQuery each</p> <p>jQuery each</p> <p>jQuery each</p> var arr = [1,2,3] var nodeList = document.getElementsByTagName('p') var $p = $('p')//要對這三個對象進行遍歷,要寫三個遍歷方法 arr.forEach(function(item){console.log(item) })//nodeList不是純數組 var i,length = nodeList.length; for(i;i<length;i++){console.log(nodeList[i]) }$p.each(function(key,p){console.log(key,p) })//順序遍歷有序集合 //使用者不必知道集合的內部結構 function each(data) {var $data = $(data) //生成迭代器$data.each(function(key, value) {console.log(key,value)}) }each(arr) each(nodeList) each($p)

UML類圖

代碼演示

class Iterator {constructor(container) {this.list = container.list;this.index = 0;}next() {if (this.hasNext()) {return this.list[this.index++]}}hasNext() {if (this.index >= this.list.length) {return false;}return true;} }class Container {constructor(list) {this.list = list}//生成遍歷器getIterator() {return new Iterator(this)} }let arr = [1, 2, 3, 4, 5, 6] let container = new Container(arr) let iterator = container.getIterator() while (iterator.hasNext()) {console.log(iterator.next()) }

應用場景

  • jQuery each
function each(data){var $data = $(data) //生成迭代器$data.each(function(key,p){console.log(key,p)}) }
  • ES6 Iterator
  • ES6語法中,有序集合的數據類型已經有很多
  • Array、Map、Set、String、TypedArray、argument、 NodeList
  • 以上數據類型都有[Symbol.Iterator]屬性
  • 屬性值是函數,執行函數返回一個迭代器
  • 這個迭代器就有next方法可順序迭代子元素
  • 可運行Array.prototype[Symbol.iterator]來測試
  • for...of 消費 iterator
  • ES6 Iterator與Generator
  • iterator的價值不限于尚書幾個類型的遍歷,還有Generator函數的使用
  • 即只要返回的數據符合Iterator接口的要求
  • 即可使用Iterator語法,這就是迭代器模式

設計原則驗證

  • 迭代器對象和目標對象分離
  • 迭代器將使用者與目標對象隔離開
  • 符合開放封閉原則

狀態模式

  • 一個對象有狀態變化
  • 每次狀態變化都會觸發一個邏輯
  • 不能總是用if...else來控制

示例

交通信號燈不同顏色的變化

UML類圖

代碼演示

//狀態 class State {constructor(state) {this.state = state}getState() {return this.state}handle(context) {console.log(`turn to ${this.state} light`)context.setState(this)} } //主體 class Context {constructor() {this.state = null}getState() {return this.state}setState(state) {this.state = state} }let context = new Context()let green = new State('green') let yellow = new State('yellow') let red = new State('red')green.handle(context); console.log(context.getState())yellow.handle(context); console.log(context.getState())red.handle(context); console.log(context.getState())

應用場景

  • 有限狀態機
  • 有限個狀態,以及在這些狀態之間的變化,如交通信號燈
  • 使用開源lib:javascript-state-machine
//狀態機模型 import StateMachine from 'javascript-state-machine'var fsm = new StateMachine({init: '收藏', //初始狀態,待收藏transitions: [{name: 'doStore',from: '收藏',to: '取消收藏'},{name: 'deleteStore',from: '取消收藏',to: '收藏'}],method: {//執行收藏onDoStore: function() {alert('收藏成功')updateText()},onDeleteStore: function() {alert('取消收藏')updateText()}}})var $btn = $('#btn');//點擊事件 $btn.click(function() {if (fsm.is('收藏')) {fsm.doStore()} else {fsm.deleteStore()} })//更新文案 function updateText() {$btn.text(fsm.state) }//初始化文案 updateText()
  • 寫一個簡單的Promise
  • Promise是一個一個有限狀態機
  • Promise有三種狀態:pending、fullfilled、rejected
  • pending -> fullfilled 或者 pending -> rejected,不可逆向變化
class MyPromise {constructor(fn) {this.successList = []this.failList = []fn(() => {//resolve函數fsm.resolve(this)}, () => {//reject函數fsm.reject(this)})}then(successFn, failFn) {this.successList.push(successFn)this.failList.push(failFn)} }//模型 var fsm = new StateMachine({init: 'pending',transitions: [{name: 'resolve',from: 'pending',to: 'fullfilled'}, {name: 'reject',from: 'pending',to: 'rejected'}],methods: {onResolve: function(state, data) {//參數state - 當前狀態示例;data - fsm,resolve(xxx)執行時傳遞過來的參數data.successList.forEach(fn => fn());},onReject: function(satte, data) {//參數state - 當前狀態示例;data-fsm.reject(xxx)執行時傳遞過來的參數data.failList.forEach(fn => fn())}} })function loadImg(src) {const promise = new MyPromise(function(resolve, reject) {let img = document.createElement('img');img.onload = function() {resolve(img)}img.onerror = function() {reject(img)}img.src = src})return promise }let src = "https://www.xxxx.com/dsadfa/dafdafd.png"; let result = loadImg(src); result.then(function() {console.log('ok1') }, function() {console.log('fail1') }) result.then(function() {console.log('ok2') }, function() {console.log('fail2') })

設計模式驗證

  • 將狀態對象和主題對象分離,狀態的變化邏輯單獨處理
  • 符合開放封閉原則

其他設計模式

  • 不常用
  • 對應不到經典場景

創建型:

  • 原型模式
結構型:
  • 橋接模式
  • 組合模式
  • 享元模式
行為型
  • 策略模式
  • 模板方法模式
  • 職責鏈模式
  • 命令模式
  • 備忘錄模式
  • 中介者模式
  • 訪問者模式
  • 解釋器模式

原型模式

  • clone自己,生成新對象(new開銷比較大)
  • java默認有clone接口,不用自己實現

使用場景

Object.create
  • Object.create用到了原型模式的思想(雖然不是java中的clone)
//基于一個原型創建一個對象 const prototype = {getName: function() {return this.first + '' + this.last;},say: function() {console.log('hello')} }//基于原型創建x var x = Object.create(prototype) x.first = 'A' x.last = 'B' console.log(x.getName()) x.say()//基于原型創建y var y = Object.create(prototype) y.first = 'C' y.last = 'D' console.log(y.getName()) y.say()

對比JS中的原型prototype

  • prototype 可以理解為ES6 class的一種底層原理
  • class是實現面向對象的基礎,并不是服務于某個模式

橋接模式

  • 用于把抽象化與實現化解耦
  • 使得兩者可以獨立變化
  • 在一些業務中比較常用

應用場景

//普通實現 class ColorShape {yellowCircle() {//...畫黃圓}redCircle() {//...畫紅圓}yellowTriangle() {//...畫黃三角形}redTriangle() {//...畫紅三角形} } //測試 let cs = new ColorShape() cs.yellowCircle() cs.redCircle() cs.yellowTriangle() cs.redTriangle()

//橋接模式 class Color {constructor(color) {this.color = color;} } class Shape {constructor(name, color) {this.name = name;this.color = color;}draw() {//畫圖...} } //測試代碼 let red = new Color("red") let yellow = new Color("yellow") let circle = new Shape('circle', red) circle.draw() let triangle = new Shape('triangle', yellow) triangle.draw()

顏色和圖形自由組合,復雜性少很多,后面增加圖形也很好處理

設計原則驗證

  • 抽象和實現分離,解耦
  • 符合開放封閉原則

組合模式

  • 生成樹形結構,表示“整體-部分”關系
  • 讓整體和部分都具有一致的操作方式

示例:

應用場景

  • 虛擬DOM中的vnode是這種形式,但數據類型簡單
  • 用JS實現一個菜單文件夾管理,不算經典應用,與業務相關
<div id="div1" class="container"><p>123</p><p>456</p> </div> {tag: 'div',attr: {id: 'div1',className: 'container'},children: [{tag: 'p',attr: {},children: ['123']}, {tag: 'p',attr: {},children: ['456']}] }
  • 整體和單個節點的操作是一致的
  • 整體和單個節點的數據結構也保持一致
  • 設計原則驗證
  • 將整體和單個節點的操作抽象出來
  • 符合開放封閉原則

享元模式

  • 共享內存(主要考慮內存,而非效率)
  • 相同的數據,共享使用

JS中不用太多考慮內存開銷

演示

//無限下拉列表,將事件代理到高層次節點上 //如果都綁定到'<a>'標簽,對內存開銷大<div id="div1"><a href="#">a1</a><a href="#">a2</a><a href="#">a3</a><a href="#">a4</a><!--無限下拉列表--> </div>< script >var div1 = document.getElementById('div1')div1.addEventListener('click', function(e) {var target = e.targetif (e.nodeName === 'A' {alert(target.innerHtml)})}) </script>

設計原則驗證

  • 將相同的部分抽象出來
  • 符合開放封閉原則

策略模式

  • 不同策略分開處理
  • 避免出現大量if...else或者switch...case

演示

class User {constructor(type) {this.type = type}buy() {if (this.type === 'oridinary') {console.log('普通用戶購買')} else if (this.type === 'member') {console.log('會員用戶購買')} else if (this.type === 'vip') {console.log('vip用戶購買')}} }//測試代碼 var u1 = new User('oridinary') u1.buy() var u2 = new User('member') u2.buy() var u3 = new User('vip') u3.buy()

改成下面這種形式:

class OrdinaryUser {buy() {console.log('普通用戶購買')} } class MemberUser {buy() {console.log('會員用戶購買')} } class VipUser {buy() {console.log('vip用戶購買')} }var u1 = new OrdinaryUser() u1.buy()var u2 = new MemberUser() u2.buy()var u3 = new VipUser() u3.buy()

設計原則驗證

  • 不同策略,分開處理,而不是混合在一起
  • 符合開放封閉原則

模板方法模式和職責鏈模式

模板方法模式:

class Action {handle() {handle1();handle2();handle3();}handle1() {console.log('1')}handle2() {console.log('2')}handle3() {console.log('3')} }

職責鏈模式

  • 一步操作可能分為多個職責角色來完成
  • 把這些角色都分開,然后用一個鏈串起來
  • 將發起者和各個處理者進行隔離
演示:
//請假審批,需要組長審批、經理審批、最后總監審批 class Action {constructor(name) {this.name = name;this.nextAction = null}setNextAction(action) {this.nextAction = action}handle() {console.log(`${this.name} 審批`)if (this.nextAction != null) {this.nextAction.handle()}} }let a1 = new Action('組長') let a2 = new Action('經理') let a3 = new Action('總監') a1.setNextAction(a2) a2.setNextAction(a3) a1.handle()

應用場景

JS中的鏈式操作
  • 職責鏈和業務結合較多,JS中能聯想到鏈式操作
  • jQuery的鏈式操作,Promise.then的鏈式操作

設計原則驗證

  • 發起者和各個處理者進行隔離
  • 符合開放封閉原則

命令模式

  • 執行命令時,發布者和執行者分開
  • 中間加入命令對象,作為中轉站

class Receiver {exec() {console.log('執行')} }class Command {constructor(receiver) {this.receiver = receiver}cmd() {console.log('觸發命令')this.receiver.exec()} }class Invoke {constructor(command) {this.command = command;}invoke() {console.log('開始')this.command.cmd();} }let soldier = new Receiver() let trumpeter = new Command(soldier) let general = new Invoke(trumpeter) general.invoke()

應用場景

  • 網頁富文本編輯器操作,瀏覽器封裝了一個命令對象
  • document.execCommand("bold")
  • document.execCommand("undo")

設計原則驗證

  • 命令對象與執行對象分開,解耦
  • 符合開放封閉原則

備忘錄模式

  • 隨時記錄一個對象的狀態變化
  • 隨時可以恢復之前的某個狀態(如撤銷功能)

演示

一個編輯器

//備忘類 class Memento {constructor(content) {this.content = content;}getContent() {return this.content;} }//備忘列表 class CareTaker {constructor() {this.list = [];}add(memento) {this.list.push(memento)}get(index) {return this.list[index]} }//編輯器 class Editor {constructor() {this.content = null}setContent(content) {this.content = content}getContent(content) {return this.content}saveContentToMemento() {return new Memento(this.content)}getContentFromMenmeto(memento) {this.content = memento.getContent()} } //測試代碼 let editor = new Editor() let careTaker = new CareTaker() editor.setContent('111') editor.setContent('222') careTaker.add(editor.saveContentToMemento()) //存儲備忘錄 editor.setContent('333') careTaker.add(editor.saveContentToMemento()) //存儲備忘錄 editor.setContent('444') console.log(editor.getContent()) editor.getContentFromMenmeto(careTaker.get(1)) //撤銷 console.log(editor.getContent()) editor.getContentFromMenmeto(careTaker.get(0)) //撤銷 console.log(editor.getContent())

設計原則驗證

  • 狀態對象與使用者分開,解耦
  • 符合開放封閉原則

中介者模式

演示

class Mediator {constructor(a, b) {this.a = a;this.b = b;}setA() {let number = this.b.number;this.a.setNumber(number * 100);}setB() {let number = this.a.number;this.b.setNumber(number / 100);} }class A {constructor() {this.number = 0;}setNumber(num, m) {this.number = num;if (m) {m.setB()}} }class B {constructor() {this.number = 0;}setNumber(num, m) {this.number = num;if (m) {m.setA();}} }let a = new A(); let b = new B(); let m = new Mediator(a, b);a.setNumber(100, m); console.log(a.number, b.number); b.setNumber(300, m); console.log(a.number, b.number)

設計原則驗證

  • 將各關聯對象通過中介者隔離
  • 符合開放封閉原則

訪問者模式

  • 將數據操作和數據結構分離
  • 使用場景不多

解釋器模式

  • 描述語言語法如何定義,如何解釋和編譯
  • 用于專業場景

綜合應用

關于面試

  • 能說出課程重點講解的設計模式即可

日常使用

  • 了解重點設計模式,要強制自己模仿、掌握
  • 非常用的設計模式,視業務場景選擇性使用

總結

以上是生活随笔為你收集整理的Javascript设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产凹凸一区二二区 | 欧美xxxx黑人xyx性爽 | 青娱乐在线视频观看 | 欧美国产成人精品一区二区三区 | www.五月激情 | 污污在线看 | 在线看a网站 | fc2ppv色の美マンに中出し | 久久成人久久爱 | 国产精品入口麻豆九色 | 欧美日韩一区二区久久 | 免费观看黄色一级片 | 亚洲污片 | 国产婷婷在线观看 | 一级片免费播放 | 最新中文字幕免费视频 | 欧美顶级毛片在线播放 | 少妇一级淫片 | 日韩高清精品免费观看 | 久久人人爽人人人人片 | 天天av天天干 | 日本一级淫片1000部 | 久久99免费| 精品久久视频 | 国产少妇在线 | 国产喷水福利在线视频 | 一区二区三区免费视频观看 | 国产高清一| 日本久久久久久久久久久 | 日韩精品乱码久久久久久 | 久久精品国产成人av | 色哟哟欧美精品 | xxxx国产| 色综合久久中文字幕无码 | 国产精品第1页 | 国内免费av | 色版视频在线观看 | 午夜av激情| 把高贵美妇调教成玩物 | 国产视频久久 | 色视频国产 | 国产极品网站 | 久久久久久影院 | 影音先锋人妻啪啪av资源网站 | www.99视频| 三级欧美韩日大片在线看 | 住在隔壁的她动漫免费观看全集下载 | 奇米777色| 7799精品视频天天看 | 一级久久久 | 国偷自拍第113页 | 午夜精品福利一区二区三区蜜桃 | 91pao| 国产精品毛片一区视频播 | 日韩在线一级 | 日本一区二区视频免费 | 国产在线国偷精品免费看 | 丰满人妻一区二区 | 欧美插插视频 | 日产久久久久久 | 超碰在线网址 | 国产性生活 | 夜夜高潮夜夜爽 | 亚洲欧美校园春色 | 刘亦菲毛片 | 欧美中出| 日本男男激情gay办公室 | 91久久精品美女高潮 | 日韩精品中文字幕一区二区三区 | 免费成人高清 | 樱桃av| 中文字幕在线观看av | 国产乱人乱精一区二视频国产精品 | 久久精品视频18 | 99热这里有精品 | 99热自拍偷拍 | 免费激情片| 午夜aaa | aaa级黄色片 | 一级片免费观看 | 亚洲国产视频一区二区 | 国产日韩欧美一区 | 久草毛片 | 精品久久久久一区二区 | 亚洲欧美天堂网 | 在线播放视频高清在线观看 | 在线视频区 | 最近日韩中文字幕 | 国产精品久久久久久亚洲伦 | 色干干| 亚洲国产一区二区三区在线观看 | 91网址在线 | 免费av网站在线 | 久精品免费视频 | 亚洲一区二区免费视频 | 黑人狂躁日本妞hd | 日韩精品人妻一区二区三区免费 | 亚洲大尺度在线观看 | 国产日日夜夜 |