設計模式在vue中的應用(七)

hailx發表於2019-03-03

前言

目錄整理:
設計模式在vue中的應用(一)
設計模式在vue中的應用(二)
設計模式在vue中的應用(三)
設計模式在vue中的應用(四)
設計模式在vue中的應用(五)
設計模式在vue中的應用(六)
設計模式在vue中的應用(七)

為什麼要寫這些文章呢。正如設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結(來自百度百科)一樣,也是想通過分享一些工作中的積累與大家探討設計模式的魅力所在。
在這個系列文章中為了輔助說明引入的應用場景都是工作中真實的應用場景,當然無法覆蓋全面,但以此類推也覆蓋到了常見的業務場景



一,介面卡模式

介面卡相當於和事佬的存在,生活中介面卡常見情景:

  • 兩口插座轉三口
  • android充電線介面轉iphone

通過上面兩個例子應該很容易發現介面卡應用於存在不相容的場景,在程式碼中的表現就是多個物件每個物件要執行的方法不同,這時就要通過介面卡對要呼叫的方法進行統一
定義(來自百度百科):

介面卡模式(有時候也稱包裝樣式或者包裝)將一個類的介面適配成使用者所期待的。一個適配允許通常因為介面不相容而不能在一起工作的類工作在一起,做法是將類自己的介面包裹在一個已存在的類中

場景

假設在專案中我們原本使用了Swiper這個元件,使用方式如下:

<swiper :prop-x="px" :prop-y="py" :prop-z="pz" />
複製程式碼

後來又有了一個功能更強大,效能更好的滑動元件——NbSwiper,使用方式如下:

<nb-swiper :prop-x="px" :prop-yy="pz" :prop-z="pw" />
複製程式碼

對比可以發現

Swiper NbSwiper 元件data
prop-x prop-x px
prop-y py
prop-z prop-yy pz
prop-z pw

現在需求是要把專案中所有的Swiper元件替換為NbSwiper如上表:

兩個元件處理除了`prop-x`使用相同,另外幾個屬性`prop-y`、`prop-yy`、`prop-z`都有一定的區別。

如果直接在程式碼中一個一個的更改,工作量有點大,而且很難保證在處理一些相容問題上不出現bug
複製程式碼
介面卡模式上場

要解決這個問題我們可以選擇將Swiper作為一個裝飾元件

// Swiper.vue
// 專案原本使用的Swiper元件會被替換掉,我們自己封裝一個Swiper元件
<template>
  <!-- 進行轉換 -->
  <nb-swiper :prop-x="propX" :prop-yy="propZ" :prop-z="propW" />
</tempalte>
<script>
  export default {
    props: {
      // 接受原本Swiper的props和NbSwiper支援的props
      propX: String,
      propY: String,
      propYy: String,
      propZ: String,
      propW: String,
    }
    ...
  }
</script>
複製程式碼

現在我們的工作只需在程式碼中增加對NbSwiper的新屬性值的相容

二,裝飾者模式

定義(來自百度百科):

裝飾模式指的是在不必改變原類檔案和使用繼承的情況下,動態地擴充套件一個物件的功能。它是通過建立一個包裝物件,也就是裝飾來包裹真實的物件

場景 1

<input />
複製程式碼

瀏覽器原生Input沒有驗證功能或者驗證功能比較弱,我們現在要賦予它比較強的驗證功能怎麼辦——裝飾者模式

設計實現

element-ui、iView等各類UI框架大家都有用過,這些框架提供的Input元件應該也不會陌生吧,互動友好功能強大。今天我們的設計會與他們有點與眾不同

// 原生input需要驗證功能,我們用帶有驗證能力的valid-input包裹
<valid-input>
  <input v-model="username" type="text" />
</valid-input>
複製程式碼

簡單思考下
valid-input要做驗證需要:

  • 對那個值進行驗證
  • 用什麼規則進行驗證
//input 與username進行繫結
<valid-input field="username" options="[{ rule: required, message: '使用者名稱必須' }]">
  <input v-model="username" type="text" />
</valid-input>
複製程式碼

如果哪天我不需要驗證功能只需刪掉valid-input,這樣很靈活的實現功能的擴充套件

具體實現過程(之前寫過一篇相關主題的文章,連結找不到了,程式碼實現如果需要後期補上

場景 2

checkbox、radio瀏覽器原生長的醜不說而且在不同的瀏覽器上還不一樣,這對於我們優秀的產品來說是不能忍的

// 常規解決方案,自己通過CSS模式checkbox的互動
<label class="checkbox-wrapper">
  <span class="checkbox">
    <span class="checkbox-inner"></span>
    <input type="checkbox" class="checkbox-input">
  </span>
  Checkbox
</label>
複製程式碼

這樣的場景實現相信大家也不會陌生,現在的問題的是:

我原本使用checkbox只需
<input type="checkbox" class="checkbox-input">

而現在多了這麼多層標籤巢狀,還有很多css樣式,在使用中很難保證不出錯
複製程式碼
裝飾者模式實現
// stage.vue
// decoratorCheckbox的實現簡化每次使用要寫很多標籤和註明class

<tempalte>
  <div>
    <decorator-checkbox>
      <input type="checkbox" class="checkbox-input">
    </decorator-checkbox>
  </div>
</template>
複製程式碼

具體實現過程(之前寫過一篇相關主題的文章,連結找不到了,程式碼實現如果需要後期補上

三,代理模式

先看定義(來自百度百科):

所謂的代理者是指一個類別可以作為其它東西的介面。代理者可以作任何東西的介面:網上連線、儲存器中的大物件、檔案或其它昂貴或無法複製的資源。

代理模式和裝飾者模式的UML圖看起來很相似,有什麼區別呢?

懵懂騷年喜歡一位漂亮姑涼

裝飾者模式:不管這位姑涼怎麼化妝,穿長袖還是短袖(裝飾)騷年每次遠觀看到的終究是姑涼本人

代理模式:騷年按奈不住躁動的心要開始行動了,騷年想到了一個方法首先策反姑涼的好友閨蜜作
        為自己的代理達傳達一些小紙條什麼的,小紙條最終有沒有送到姑涼手中騷年並不能確認
        ,可是少年依舊通宵寫著紙條。參見電影《你好,之華》年輕之華
          
複製程式碼

情景

我們從後端拿到了一堆資料

  • 資料不為空——進行列表顯示
  • 資料為空——顯示資料為空的提示
// list.vue
<template>
 <div>
   <div v-if="isEmpty">資料為空</div>
   <div v-else>
     <div v-for="item in data">
       ... do something  
     </div>
   </div>
 </div>
</tempalte>
<script>
  export default{
    props: {
      data: Array
    },
    computed: {
      isEmpty() {
        return this.data.length < 1
      }
    }
  }
</script>
複製程式碼

可以發現List元件做了兩件事:資料為空的處理、資料不為空的處理,這種設計是不太友好的

Proxy

// ProxyList.vue
<template>
 <div>
   <empty v-if="isEmpty" />
   <list v-else :data="data" />
 </div>
</tempalte>
<script>
  import Empty from './Empty'
  import List from './List'
  
  export default{
    props: {
      data: Array
    },
    computed: {
      isEmpty() {
        return this.data.length < 1
      }
    },
    components:{
      Empty,
      List
    }
  }
</script>

複製程式碼

對於資料data的使用者來說,只需關心拿資料渲染列表,資料為空是什麼樣的完全不關心

結尾

這篇一次介紹了三種設計模式:介面卡模式、裝飾者模式、代理模式,大多時候我們很容易將他們搞混淆,這也是將他們放在一起的原因。結合上面的例子再來看一下他們的不同點

介面卡模式:將多個物件的不同方法呼叫(objA.methodA(),objB.methodB()),適配成統一調
            用(objA.methodA(),adapterObjB.methodA())

裝飾者模式:在不修改原物件的基礎上動態的新增功能
            功能:擴充套件功能
            要求:裝飾者要實現和被裝飾物件相同的方法

代理模式:為其他物件提供一種代理以控制對這個物件的訪問
          功能:控制被代理物件的訪問
          要求:與裝飾者模式一樣要實現和被代理物件相同的方法
複製程式碼

本文實現同樣適用於react,為什麼文章以vue做題?vue的template讓我們在理解一些概念的時候可能會有點不適應,而react的jsx可以看做就是在寫JavaScript對各種概念實現更靈活
友情提示:設計模式在vue中的應用應該會寫一個系列,喜歡的同學記得關注下

相關文章