做爲建立型設計模式,帶有工廠名字的設計模式共有三個,分別是git
其中的 Simple Factory並非GoF一書中的模式,可是它是最基礎最經常使用的,而且也是按部就班的瞭解另外兩個工廠的必要基礎,全部放在一塊兒講它們是比較科學的。github
三者經常是容易搞混的,我就見過若干個搞混的案例。要麼,比起這更難的,是不太容易弄明白使用的場景和目的。本文試圖經過一個案例,講清楚三者的內涵,可是不許備講解它的外延。json
假設咱們想要作一個圖形編輯器,咱們把它的需求壓低到極爲簡潔的形式,只要和當前要描述的問題無關的,咱們都不會引入:設計模式
那麼,系統中必然須要以下的Shape類:編輯器
class Shape{draw(){}} class Rect extends Shape{draw(){}} class Circle extends Shape{draw(){}}
以及,系統中必然須要以下的Color類:函數
class Color{fill(){}} class Red extends Color{fill(){}} class Yellow extends Color{fill(){}}
咱們首先從Shape開始。假設須要建立一個矩形,咱們能夠這樣作:工具
var rect = new Rect()
須要一個圓形也簡單:編碼
var rect = new Circle()
實際上,咱們一般是在界面上,通常是工具欄上,放置兩個按鈕,讓用戶選擇哪一個按鈕,而後建立此形狀。用戶選擇了矩形,接下來建立就是矩形,選擇的是圓形,那麼建立就是圓形。因此這樣的代碼必定是存在的:設計
if (userSelected = "rect") return new Rect() if (userSelected = "circle") return new Circle()
Simple Factory的價值就是讓調用者從建立邏輯中解脫,只要傳遞一個參數,就能夠得到建立對象。實際上,從對象職責來講,這段代碼不該該是Rect或者是Circle的,也不該該是UI類的,UI類在不一樣的應用中是不同的,可是咱們知道做爲頂層類,須要負責UI顯示和事件,不該該負責建立對象的邏輯。實際上,不少代碼放到此處,特別容易致使代碼擁擠,主控類職責過多的問題。code
最好引入一個新的類,像是這樣:
class ShapeCREATEOR{ create(userSelected){ if (userSelected = "rect") return new Rect() if (userSelected = "circle") return new Circle() } }
這個類的全部邏輯,都是專門用於建立其餘類。由於很是常見,人們爲他取名爲Factory,其餘被建立的類被稱爲Product。因此慣例上來講,此類的名字會冠以工廠名:
class ShapeFactory
根據傳入的參數,決定建立哪個產品類,此類就被稱爲簡單工廠類(Simple Factory)。有了工廠類,使用者就能夠直接使用工廠類得到須要的對象:
var sf = new ShapeFactory() var rect = sf.create("rect")
因而,全部須要建立矩形的場合,你知道,一個UI App,除了工具欄,還有菜單,都只要寫這樣的代碼就能夠建立了。而沒必要處處根據userSelected來作分支了。這就是使用工廠的好處。若是支持命令建立,甚至使用json文件中恢復對象時,原本也須要傳遞字符串來決定建立對象時,就顯得簡單工廠的好處了。
簡單工廠根據傳入的參數決定實例化哪個類,而factory method有子類來決定實例化哪個類。
class Shape{draw(){}} class Rect extends Shape{draw(){}} class Circle extends Shape{draw(){}} class ShapeFactory{ createShape(){} } class RectFactory extends ShapeFactory{ createShape(){return new Rect()} } class CircleFactory extends ShapeFactory{ createShape(){return new Circle()} }
調用者須要建立Rect,只要這樣:
var f = new RectFactory() f.createShape()
這是factory method的定義:
建立一個接口,可是由子類決定實例化哪個類
這裏提到的接口是ShapeFactory.createShape,提到的子類爲:RectFactory,CircleFactory。這樣作就意味着,在工廠內沒必要根據傳入參數分支,它做爲子類自己就知道要建立的是哪個產品。使用對應的工廠,建立須要的類。
要是咱們建立的類型不只僅是Shape,還有Color的話,AbstractFactory就有價值。AbstractFactory提供一個接口a,此接口能夠建立一系列相關或者相互依賴的對象b,使用用戶不須要指定具體的類便可建立它們c。
咱們先看代碼:
class Shape{draw(){}} class Rect extends Shape{draw(){}} class Circle extends Shape{draw(){}} class ShapeFactory{ createShape(type){ if (shape == "rect"){ return new Rect() }else{ return new Circle() } } } class Color{fill(){}} class Red extends Color{fill(){}} class Yellow extends Color{fill(){}} class ColorFactory { creatColor(type){ if (shape == "Red"){ return new Red() }else if (shape == "Yellow"{ return new Yellow() } } }
若是但願客戶能夠一個單一接口來訪問Color和Shape,能夠引入一個抽象工廠:
class AbstractFactory{ createShape(){} createColor(){} }
要求兩個工廠實現此抽象工廠:
class ShapeFactory extends AbstractFactory{ createShape(type){ if (shape == "rect"){ return new Rect() }else{ return new Circle() } } createColor(){ return null } } class ColorFactory extends AbstractFactory{ createShape(type){return null} creatColor(type){ if (shape == "Red"){ return new Red() }else if (shape == "Yellow"{ return new Yellow() } } }
本身不具有的能力,不實現便可,這裏就是返回一個null。須要一個建立工程的簡單工廠
class FactoryProducer{ getFactory(type){ if (type == "color")return new ColorFactory() else return new ShapeFactory() } }
沒有抽象工廠,那麼代碼是這樣的,全部的Factory類的建立都是硬編碼的
var sf = new ShapeFactory() var r = sf.createColor("Rect") r.draw() var cf = new ColorFactory() var c = cf.createColor("Red") c.fill()
有了抽象工廠,那麼客戶的使用就是這樣
var fp = new FactoryProducer() var sf = fp.getFactory("shape") var r = sf.createColor("Rect") r.draw() var cf = fp.getFactory("color") var c = cf.createColor("Red") c.fill()
好處是,硬編碼建立的類只有一個,就是FactoryProducer。
其中難懂的部分,作一個進一步說明:
本文host於 https://github.com/1000copy/d... ,歡迎folk。