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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

(十三)其他设计模式

發布時間:2023/12/31 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (十三)其他设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

其他設計模式

  • 其他設計模式
    • 優先級劃分依據
    • 設計模式有:
      • 創建型
      • 結構型
      • 行為型
  • 原型模式
    • 對比js中的原型prototype
  • 橋接模式
    • 設計原則驗證
  • 組合模式
  • 享元模式
  • 策略模式
  • 模板方法模式
  • 職責鏈模式
  • 命令模式
  • 備忘錄模式
  • 訪問者模式
  • 中介者模式
  • 解釋器模式
  • 關于面試
  • 日常使用

其他設計模式

優先級劃分依據

  • 不常用
  • 是找不到經典應用場景

設計模式有:

創建型

  • 原型模式

結構型

  • 橋接模式
  • 組合模式
  • 享元模式

行為型

  • 策略模式 、模板方法模式 、職責鏈模式
  • 命令模式 、備忘錄模式 、中介者模式
  • 訪問者模式 、解釋器模式

原型模式

  • clone自己,生成一個新對象
  • java默認有clone接口,不用自己實現

基于一個對象創建一個重復的對象,重新new代價較大的情況下,就拷貝一份。具體實現就是自己實現一個 clone 自己的 API ,外部調用時克隆自己。如 java 內置了clone方法,不用自己定義。

JS 用到不多,因為 JS 中基本不會遇到new代價很大的場景。基本遇到需要創建時,直接重新new就可以了。

不過Object.create用到了原型模式的思想(雖然不是 java 中的 clone ),基于一個原型創建一個對象

// `Object.create` 用到了原型模式的思想(雖然不是 java 中的 clone ) // 基于一個原型創建一個對象 var 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是實現面向對象的基礎,而不是服務于某個模式
  • 若干年后ES6全面普及,大家可能會忽略掉prototype
  • 但是Object create卻會長久存在

和 js 的 prototype 不一樣。在 ES6 語法中,全部使用 class ,prototype 就成了一種底層的實現機制,而不再對開發人員開放。可能若干年后,ES6 標準統一天下,倒是很多初學者都不知道 prototype 是怎么回事兒。因此,目前 JS prototype 可以看做和 class 是同樣的功能,并不是原型模式。

prototype 將會隱藏,而 Object.create 將會長久保留。

橋接模式

  • 用于把抽象化與實現化解耦
  • 使得二者可以獨立變化
  • (未找到JS中的經典應用)

橋接(Bridge)是用于把抽象化與實現化解耦,使得二者可以獨立變化。在常見的 JS 代碼中找不到合適的例子,下面例子比較合適。

畫有顏色的圖形,第一種設計方式如下

示例代碼

class ColorShape {yellowCircle() {console.log('yellow circle')}redCircle() {console.log('red circle')}yellowTriangle() {console.log('yellow triangle')}redTriangle() {console.log('red triangle')} }// 測試 let cs = new ColorShape() cs.yellowCircle() cs.redCircle() cs.yellowTriangle() cs.redTriangle()

第二種設計方式

示例代碼

class Color {constructor(name) {this.name = name} } class Shape {constructor(name, color) {this.name = namethis.color = color}draw() {console.log(`${this.color.name} ${this.name}`)} }// 測試代碼 let red = new Color('red') let yellow = new Color('yello') let circle = new Shape('circle', red) circle.draw() let triangle = new Shape('triangle', yellow) triangle.draw()

顯然,第二種方式更加符合開放封閉原則。

另外一個原則 —— 少繼承,多聚合

設計原則驗證

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

組合模式

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

組合模式,將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。

按照傳統組合模式中數據結構應該是這樣的

例子

  • JS經典應用中,未找到這么復雜的數據類型,
  • 虛擬 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']}] }
  • 整體和單個節點的操作是一致的
  • 整體和單個節點的數據結構也保持一致

關鍵的一點,對于整體還是單個節點的操作都是一致的。例如,以上結構無論是拿到div節點還是p節點,數據結構都是一樣的。

設計原則驗證
將整體和單個節點的操作抽象出來
符合開放封閉原則

享元模式

  • 共享內存(主要考慮內存,而非效率)
  • 相同的數據,共享使用
  • (JS中未找到經典應用場景)

享元模式(Flyweight),運行共享技術有效地支持大量細粒度的對象,避免大量擁有相同內容的小類的開銷(主要考慮空間效率,如內存),使大家共享一個類(元類) 。

就是為了避免開銷過大而共享一些數據,未能找到 JS 中特別符合的例子。但是符合享元模式設計思想的例子有:

無限下拉列表,將事件代理到高層節點上,如下代碼。如果都綁定到<a>標簽,對內存開銷太大。

<!-- 無限下拉列表,將事件代理到高層節點上 --> <!-- 如果都綁定到`<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>

注意,在此前的代理模式中也用到這個 demo ,不過兩者不沖突,體現的是兩種設計思想而已。

設計原則驗證
將相同的部分抽象出來
符合開放封閉原則

策略模式

  • 不同策略分開處理
  • 避免出現大量if...else或者switch...case
  • (JS中未找到經典應用場景)

主要解決多個if...else或者switch...case的問題。

多用于具體的業務代碼中,因為本教程沒有做一個實戰項目,因此先舉個例子說明一下。例如一次購買行為,針對普通用戶、會員和 vip 都有不同的折扣。普通的實現方式如:

class User {constructor(type) {this.type = type}buy() {if (this.type === 'ordinary') {console.log('普通用戶購買')} else if (this.type === 'member') {console.log('會員用戶購買')} else if (this.type === 'vip') {console.log('vip 用戶購買')}} }// 測試代碼 var u1 = new User('ordinary') 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()

關鍵在于:把 if…else 拆分開,分出不同的策略,每個策略單獨處理,而不是混在一起

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

模板方法模式

模板方法模式想要表述的其實特別簡單,就是將分散的一些操作集中起來,例如

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

職責鏈模式

  • 一步操作可能分位多個職責角色來完成
  • 把這些角色都分開,然后用一個鏈串起來
  • 將發起者和處理者、包括多個處理者之間進行了分離

例如一個請假審批,需要組長審批、經理審批、最后總監審批。代碼如下:

// 請假審批,需要組長審批、經理審批、最后總監審批 class Action {constructor(name) {this.name = namethis.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 的鏈式操作
  • Stream pipe 鏈式操作

設計原則驗證
發起者與各個處理者進行隔離
符合開放封閉原則

命令模式

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

執行一個命令時,將命令的觸發者和執行者分開,不讓觸發者直接操作命令執行者。

代碼演示

class Receiver {exec() {console.log('執行')} } class Command {constructor(receiver) {this.receiver = receiver}cmd() {console.log('觸發命令')this.receiver.exec()} } class Invoker {constructor(command) {this.command = command}invoke() {console.log('開始')this.command.cmd()} }// 士兵 let soldier = new Receiver() // 小號手 let trumpeter = new Command(soldier) // 將軍 let general = new Invoker(trumpeter) general.invoke()

JS中的應用
網頁富文本編輯器操作,瀏覽器封裝了一個命令對象
document.execCommand(‘bold’)document.execCommand(‘undo’)

實際的例子不是很多,可列舉一個。要做一個 web 富文本編輯器,需要 JS 操作文本的樣式,例如要對選中的文本進行加粗,需要執行document.execCommand('bold')。這個 API 用到的就是命令模式,即我作為使用者是需要下達一個bold命令即可,如何執行我不用關心。撤下就執行document.execCommand('undo'),恢復就執行document.execCommand('redo')。

如何做到撤銷和恢復,可參考備忘錄模式。

設計原則驗證
命令對象與執行對象分開,解耦
符合開放封閉原則

備忘錄模式

  • 隨時記錄一個對象的狀態變化
  • 隨時可以恢復之前的某個狀態(如撤銷功能)
  • (未找到JS中經典應用),除了一些工具(如編輯器)

保存一個對象的某個狀態,以便在適當的時候恢復對象。例如撤銷功能,日常頁面用的不多,除非一些工具(如編輯器)

代碼演示一下該模式的應用:

// 狀態備忘 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() {return this.content}saveContentToMemento() {return new Memento(this.content)}getContentFromMemento(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.getContentFromMemento(careTaker.get(1)) // 撤銷 console.log(editor.getContent()) editor.getContentFromMemento(careTaker.get(0)) // 撤銷 console.log(editor.getContent())

編輯器是一個比較小眾的工具,很少有人開發這個。

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

訪問者模式

將數據操作和數據結構進行分離,使用頻率不高,就不做具體解釋了。

中介者模式

普通的多對象通訊的場景與中介者模式

代碼演示:

class A {constructor() {this.number = 0}setNumber(num, b) {this.number = numif (b) {b.setNumber(num * 100)}} }class B {constructor() {this.number = 0}setNumber(num, a) {this.number = numif (a) {a.setNumber(num / 100)}} }// 測試代碼 let a = new A() let b = new B() a.setNumber(100, b) console.log(a.number, b.number) // 100 10000 b.setNumber(100, a) console.log(a.number, b.number) // 1 100

以上代碼中,a和b產生了耦合關系。使用了之后:

代碼演示:

class Mediator {constructor(a, b) {this.a = athis.b = b}setA() {let number = this.b.numberthis.a.setNumber(number * 100)}setB() {let number = this.a.numberthis.b.setNumber(number / 100)} }class A {constructor() {this.number = 0}setNumber(num, m) {this.number = numif (m) {m.setB()}} }class B {constructor() {this.number = 0}setNumber(num, m) {this.number = numif (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) // 100 10000 b.setNumber(100, m) console.log(a.number, b.number) // 1 100

這個設計模式應該更加體現到業務代碼中,目前沒有找到特別合適的講解示例。

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

解釋器模式

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

解釋器模式描述了如何為簡單的語言定義一個文法,如何在該語言中表示一個句子,以及如何解析這些句子。

和語言的解析與編譯有關,不常用。除非你想深入這部分的學習,例如想詳細了解如何實現一個正則表達式。

關于面試

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

日常使用

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

總結

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

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