設計模式:工廠三姐妹一網打盡

做爲建立型設計模式,帶有工廠名字的設計模式共有三個,分別是git

  1. Simple Factory
  2. Factory Method
  3. Abstract Factory

其中的 Simple Factory並非GoF一書中的模式,可是它是最基礎最經常使用的,而且也是按部就班的瞭解另外兩個工廠的必要基礎,全部放在一塊兒講它們是比較科學的。github

三者經常是容易搞混的,我就見過若干個搞混的案例。要麼,比起這更難的,是不太容易弄明白使用的場景和目的。本文試圖經過一個案例,講清楚三者的內涵,可是不許備講解它的外延。json

假設咱們想要作一個圖形編輯器,咱們把它的需求壓低到極爲簡潔的形式,只要和當前要描述的問題無關的,咱們都不會引入:設計模式

  1. 能夠建立兩種形狀,矩形和圓形
  2. 能夠設置形狀的顏色,紅色和黃色

那麼,系統中必然須要以下的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

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

簡單工廠根據傳入的參數決定實例化哪個類,而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。這樣作就意味着,在工廠內沒必要根據傳入參數分支,它做爲子類自己就知道要建立的是哪個產品。使用對應的工廠,建立須要的類。

AbstractFactory

要是咱們建立的類型不只僅是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。

其中難懂的部分,作一個進一步說明:

  1. 接口a:AbstractFactory內的兩個函數createShape,createColor
  2. 一系列相關或者相互依賴的對象b: Shape系列類,Color系列類
  3. 使用用戶不須要指定具體的類便可建立它們c:實際上,用戶只要使用FactoryProducer這一個類,不須要使用任何一個工廠,以及工廠建立的類。

本文host於 https://github.com/1000copy/d... ,歡迎folk。

相關文章
相關標籤/搜索