在介紹簡單工廠模式前,咱們先來了解一下構造器模式。
有一天你在的銀行要作一個職工錄入系統,這個系統開發階段只有你本身,因此,你說了算。因而,在錄入本身的時候,你能夠這樣寫:javascript
var lee = { name: "李強", age: 26, career: "student" };
錄入同事的她時,幸福的笑了,不就是多一我的的事嘛,因而手動添加了:vue
var mei = { name: "梅梅", age: 22, career: "teacher" };
忽然想到還有不少人員沒有錄入進來,難道要本身一個個添加嗎?幸好還有構造函數,因而,建立了一個 User 函數:java
function User(name, age, career) { this.name = name; this.age = age; this.career = career; }
接下來要作的事情就是讓程序自動讀取數據庫裏面的全部員工信息,而後對 User 進行一個簡單的調用:git
var user = new User(name, age, career);
今後你不再須要手動錄入了。
像 User 這種用來初始化對象的的特殊函數,就叫作構造器。在 JavaScript 中,使用構造函數來初始化對象,就是應用了構造器模式。
雖然這個模式很簡單,可是咱們須要思考一個問題:
在建立 user 過程當中,誰變了,誰沒變?
很明顯,變的是每一個 user 的姓名、年齡、職業這些值,這是每一個人員的特性,不變的是每一個人員都有姓名、年齡、職業這些屬性,這是全部人員的共性。
那構造器作了什麼呢?
構造器不過是將 name、age、career 這些屬性的賦值過程進行封裝,確保每一個對象都具有這些屬性,確保共性不變的同時,又對 name、age、career 各自的取值保持了開放。
若是構造模式的本質是抽象不一樣對象實例之間的變與不變,那麼工廠模式的本質就是抽象不一樣類(構造函數)之間的變與不變。github
某天行長過來了解狀況,提出這個錄入系統太簡單了,並且行長和員工之間的區別不只僅須要一個簡單的 career 字段,還要有詳細的職責說明。也就是至少須要一個描述字段來闡述各自的工做。
你想了想便把 User 拆分紅了兩個具體的類:vue-router
function President(name, age, career, work) { this.name = name; this.age = age; this.career = "president"; this.work = ["喝茶", "看報紙", "..."]; } function Employee(name, age, career, work) { this.name = name; this.age = age; this.career = "employees"; this.work = ["辦存款", "放貸款", "收貸款"]; }
目前咱們只有兩個類暫時能夠知足目前行長的需求了,可是麻煩的是:難道每從數據庫拿一條數據都要人工判斷下這我的員的工種,而後在給它分配構造器嗎?不能夠的,這個工種也是一個變,要把它交給另一個函數去處理:數據庫
function Factory(name, age, career) { switch(career) { case 'president': return new President(name, age); case 'employees': return new Employee(name, age); ... } }
看起來是好了一些,至少不須要人工判斷並進行構造器分配了,可是,switch 末尾的省略號是比較恐怖的,全行有好多工種呢,難道我要手動增長這些類和 switch 嗎?
固然不是,認真看上面並不完美的代碼裏,變的是什麼?不變的又是什麼?
President 和 Employee 兩個工種的人員,仍然都有 name、age、career、work 四個屬性,只不過是每一個字段的值不一樣,並且 work 的值隨着 career 取值不一樣而改變。這樣一分析咱們封裝的仍是不夠完全,共性和個性分離的也不夠完全。
如今咱們找回 User 類把相同的邏輯封裝進去,而後在 Factory 函數中處理個性的邏輯並把建立的實例對象返回:瀏覽器
function User(name, age, career, work) { this.name = name; this.age = age; this.career = career; this.work = work; } function Factory(name, age, career) { var work; switch(career) { case 'employees': work = ["辦存款", "放貸款", "收貸款"]; case 'president': work = ["喝茶", "看報紙", "..."]; case 'chairman': work = ["喝水", "放貸簽字", "開會"]; case xxx: // 工種對應職責 ... } return new User(name, age, career, work); }
這樣一來須要咱們作的事情就簡單不少了,不用想着我拿到的數據是什麼工種分配什麼構造器了,也不須要增長額外的構造器了,而須要咱們作的只是傳參和擴展了。
工廠模式的簡單之處,在於它的概念相對好理解:將建立對象的過程單獨封裝。同時它的應用場景也很是容易識別:有構造函數的地方,咱們就應該想到簡單工廠;在寫了大量構造函數、調用了大量的 new,自覺很是不爽的狀況下,咱們就應該思考是否是可使用工廠模式重構代碼了。ide
源碼中的簡單工廠模式函數
// src/index.js export default class VueRouter { constructor(options) { this.mode = mode // 路由模式 switch (mode) { // 簡單工廠 case 'history': // history 方式 this.history = new HTML5History(this, options.base) break case 'hash': // hash 方式 this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': // abstract 方式 表明非瀏覽器環境中路由方式 this.history = new AbstractHistory(this, options.base) break default: // ... 初始化失敗報錯 } } }
源碼裏沒有把工廠方法的產品建立流程封裝出來,而是直接將產品實例的建立流程暴露在 VueRouter 的構造函數中,在被 new 的時候建立對應產品實例,至關於 VueRouter 的構造函數就是一個工廠方法。
若是一個系統不是 SPA (Single Page Application,單頁應用),而是是 MPA(Multi Page Application,多頁應用),那麼就須要建立多個 VueRouter 的實例,此時 VueRouter 的構造函數也就是工廠方法將會被屢次執行,以分別得到不一樣實例。