(四)工厂模式
工廠模式
- 工廠模式
- 工廠模式 介紹
- 概念
- 示例
- 工廠模式 演示
- 工廠模式 場景
- jQuery - `$('div')`
- `React.createElement`
- vue 異步組件
- 工廠模式 - 總結
工廠模式
- 介紹
- 演示
- 場景
- 總結
工廠模式 介紹
- 將new操作單獨封裝
- 遇到new時,就要考慮是否該使用工廠模式
概念
工廠模式是我們最常用的實例化對象模式了,是用工廠方法代替new操作的一種模式。著名的 Jive 論壇 ,就大量使用了工廠模式,工廠模式在 Java 程序系統可以說是隨處可見。因為工廠模式就相當于創建實例對象的new,我們經常要根據類Class生成實例對象,如A a=new A() 工廠模式也是用來創建實例對象的,所以以后new時就要多個心眼,是否可以考慮使用工廠模式,雖然這樣做,可能多做一些工作,但會給你系統帶來更大的可擴展性和盡量少的修改量。
示例
- 你去購買漢堡,直接點餐、取餐,不會自己親手做
- 商店要封裝做漢堡的工作,做好直接給買者
現在你要得到一個漢堡,你是跟服務員要(買)一個,還是自己動手做一個?這個問題,服務員就是工廠方法,而動手做一個其實就是new A()。
另外從快餐店考慮,你想要提供一個漢堡,是讓服務員(工廠方法)做出來(new A())給客戶,還是讓客戶自己做一個漢堡?
從這個示例很容易理解工廠模式的用意,所有的設計模式都是很講道理的,很容易理解
工廠模式 演示
常見的工廠模式的 UML 類圖如下:
不過前端 JS 使用時,左側的 Product 沒有那么復雜。沒有接口,也很少有多種子類,因此 UML 類圖可簡化為:
此處說明,之前講過前端學習設計模式不能按照 java 的方式來,UML 類圖也一樣。設計模式要學以致用,因此得考慮 JS 語法和使用場景。
- JS 沒有接口,用繼承的場景也不是特別多
- JS 是弱類型語言
因此,將 UML 類圖簡化是很有必要的,要不然你會因為不懂 java 的語法和使用場景,而搞不清楚,反而達不到學習效果!!!謹記。
代碼演示:
class Product {constructor(name) {this.name = name}init() {alert('init')}fun1() {alert('fn1')}fun2() {alert('fn2')} }class Creator {create(name) {return new Product(name)} }// 測試 let creator = new Creator() let p = creator.create('p1') p.init() p.fn1()對比剛開始的例子,Product就是漢堡,Creator就是服務員,很好理解吧。
但是在日常工作編碼中,不會再額外增加Creator的類了,create直接當做靜態的函數就行了。例如下一節的示例。
工廠模式 場景
工廠模式在日常使用非常多,凡是用到new的地方,都要考慮是否需要工廠模式。
jQuery - $('div')
- $(‘div’)和new $(‘div’)有何區別?
- 第一:書寫麻煩,jQuery的鏈式操作將成為噩夢
- 第二:一旦jQuery名字變化,將是災難性的
模擬代碼,$就是一個工廠
class jQuery {constructor(selector) {let slice = Array.prototype.slicelet 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(node) {}addClass(name) {}html(data) {}// 此處省略若干 API } window.$ = function (selector) {return new jQuery(selector) }做一個對比,如果開放給用戶的不是$,然后讓用戶自己去new jQuery(selector),帶來的問題:
- 操作復雜,代碼量增加,如$('div').append($('#p1')).html()這種操作將變得冗長繁瑣
- 一旦構造函數jQuery有變化,使用者都受牽連,不符合開閉原則
關于模式 jQuery 的源碼,說一下解讀經典框架的意義:
- 第一,學習如何實現功能
- 第二,學習它們的設計思路
- 第三,強制自己寫代碼時模擬
- 第四,自己寫出優秀的代碼
你只需要學會并且按照既有的模式來模仿,完全不需要你自己去創新。包括你看到的前端飛速進化的技術,也都不是創新,都是既有的經驗。你日常開發所遇到的各種技術問題,100% 都有既有經驗。
React.createElement
在 React 中經常使用 JSX 語法
var profile = <div><img src="avatar.png" className="profile" /><h3>{[user.firstName, user.lastName].join(' ')}</h3> </div>;這是一種語法糖,編譯之后就會是:
var profile = React.createElement("div", null,React.createElement("img", { src: "avatar.png", className: "profile" }),React.createElement("h3", null, [user.firstName, user.lastName].join(" ")) );其實React.createElement也是一個工廠,模擬代碼
class Vnode(tag, attrs, chilren) {// ...省略內部代碼... } React.createElement = function (tag, attrs, children) {return new Vnode(tag, attrs, chilren) }vue 中也用到了 vdom ,因此其中也有new vnode(...)的情況,和這個類似。
vue 異步組件
文檔 https://cn.vuejs.org/v2/guide/components-dynamic-async.html
在大型應用中,我們可能需要將應用分割成小一些的代碼塊,并且只在需要的時候才從服務器加載一個模塊。為了簡化,Vue 允許你以一個工廠函數的方式定義你的組件,這個工廠函數會異步解析你的組件定義。Vue 只有在這個組件需要被渲染的時候才會被觸發,且會把結果緩存起來供未來重渲染。例如:
Vue.component('async-example', function (resolve, reject) {setTimeout(function () {resolve({template: '<div>I am async!</div>'})}, 1000) })如你所見,這個工廠函數會收到一個 resolve 回調,這個回調函數會在你從服務器得到組件定義的時候被調用。你也可以調用 reject(reason) 來表示加載失敗。
此處不必深究使用和實現的細節,本節重點也不在于這個,而是在于工廠模式這種設計思路上。
工廠模式 - 總結
- 工廠模式是什么?
- 那種場景要考慮使用 —— new
- 介紹的幾個使用場景
- 在日常寫代碼中,要試著去模仿、應用
設計原則驗證:
- 工造函數和創建者分離
- 符合開放封閉原則
總結
- 上一篇: 虎牙直播怎么全屏播放(直播个人中心)
- 下一篇: (五)单例模式