工廠模式與OO設計原則

        發現變化隔離封裝變化是動因,關閉修改打開擴展是限制;簡單工廠很好地遵照了DRY原則,對OCP原則支持不足;工廠方法模式徹底支持了OCP原則,使用的機制是繼承;工廠方法模式都徹底支持OCP原則;LSP原則是OCP成爲可能的重要原則,抽象工廠模式、工廠方法模式徹底遵照LSP 。
      若是把建立看做一個職責,那麼系統中的哪一個對象應該擁有這個職責呢?若是把建立看做知識,那麼建立知識應該放置在什麼地方呢?說到職責咱們不得不說一下著名的GRASP原則:
GRASP是通用職責分配軟件模式(General Responsibility Assignment Software patterns)的簡稱。它包含了9大模式,分別以下所示:
        1  建立者(Creator) :決定對象應該有誰來建立的問題。
        2  信息專家(Information expert):用此模式來肯定如何給對象分配職責的問題。通常把職責分配給那些包含此職責有關信息的對象。這樣也體現了高內聚性模式。
        3 低耦合(Low coupling)
        4 控制器(Controller).
        5 高內聚(High Cohesion)
        6 多態性(polymorphism)
        7 純虛構(pure fabrication)
        8 間接性(indirection)
        9 防止變異 (protected variations)
     
能夠看出GRASP很是關注對象由誰來建立,並給出了一個職責分配的解決模型:信息專家模式;咱們沒必要深究GRASP的種種細節,咱們從上面的表述中能夠獲得這樣的啓示:
  • 對象的建立不是隨意性的,也是有規範能夠遵循的,咱們能夠從中獲得靈活性和可維護性;
  • 職責分配給這個職責相關的信息專家,即:最適合的人作最適合的事情
 
       當建立一個對象的知識散佈在系統的各處的時候,這種蔓延現象實際上說明了系統建立職責分配的混亂,缺乏一個進行擁有建立知識的信息專家(請注意這裏的表述)。 建立邏輯一般是這樣的,它包含了一系列if-else的判斷邏輯,根據運行時的具體參數來決定對象的建立。若是這部分是肯定的那麼咱們也沒必要過多的考慮它。可是若是它是變化的,好比刪減一個對象的建立或者增長一個新類型的建立,那麼這部分代碼是要被常常修改的,這種修改實際上說明咱們已經違反了OCP原則(關閉修改,打開擴展),那麼根據識別變化封裝變化的原則 咱們必須把這一部分進行抽取並進行隔離。
      翻看全部設計模式相關的書籍咱們均可以看到這樣的表述:
      工廠模式專門負責將大量有共同接口的類實例化。工廠模式能夠在運行時動態決定將哪個類實例化。
    
    
看樣子工廠模式正是咱們須要的,但咱們並不急於下手,看看是否是另有蹊徑,[接口]怎麼樣?《Java與模式》一書就是給出了這樣一個接口實現的方式。
       我習慣把接口理解成契約和行爲,建立出來不一樣的對象,對象的區別實際上行爲的差異。接口是否是能夠?假設我麼使用了接口,問題解決了麼?沒有!增長新類時一樣面臨修改代碼的問題。這個方法只是轉化了問題的形式,並無真正解決問題,使用接口咱們失去的代碼複用的優點,而大量的具體類上使用接口不是什麼好主意,雖然《Java 與模式》一書所有使用接口實現。若是要建立的對象沒有共同的業務邏輯那麼可使用一個接口來扮演抽象產品的角色,可是更多的狀況是具體產品之間是存在共有的業務邏輯,那麼這些邏輯就應該移到抽象角色裏面。
      其實咱們就是將建立知識集中並設立一個信息專家專門負責對象的建立。簡單工廠模式是咱們的第一個擁有建立知識的信息專家:
簡單工廠
      咱們考慮最簡單的抽取和隔離方法就是使用[ 簡單工廠]。簡單工廠的特色就是參數化建立對象,簡單工廠必須知道每一種產品以及什麼時候提供給Client。有人會說簡單工廠仍是換湯不換藥,添加新類的時候仍是須要修改這部分的代碼!誠然,那麼咱們得到了什麼好處呢?集中變化! 這很好的符合了DRY原則(Don't Repeat Yourself!)建立邏輯存放在單一的位置,即便它變化,咱們也只須要修改一處就能夠了。DRY 很簡單,但倒是確保咱們代碼容易維護和複用的關鍵。DRY原則同時還提醒咱們:對系統職能進行良好的分割!職責清晰的界限必定程度上保證了代碼的單一性。 這句話對咱們後續的分析極具指導意義,畢竟簡單工廠只是低層次上的代碼複用。
    
      題外話:簡單工廠的確簡單可是其背後的DRY原則在實踐中讓咱們受益不淺,去年我和個人搭檔作站點的升級工做,寫了不少重複的代碼;代碼重複,源代碼組織混亂,沒有作好規劃和職責分析是原罪。今年新項目,DRY 原則是我頭頂的達摩克利斯之劍,不作重複的事情成爲我進行項目計劃組織管理的重要標準。
    關於簡單工廠模式的階段總結:
  • 識別變化隔離變化,簡單工廠是一個顯而易見的實現方式
  • 簡單工廠將建立知識集中在單一位置符合了DRY
  • 客戶端無須瞭解對象的建立過程,某種程度上支持了OCP
  • 添加新的產品會形成建立代碼的修改,這說明簡單工廠模式對OCP支持不夠
  • 簡單工廠類集中了全部的實例建立邏輯很容易違反高內聚的責任分配原則。
     
Factory Method模式
    簡單工廠模式之因此對OCP支持不夠,就是由於它擁有了太多的知識:有多少種產品以及建立產品的時機。或者說,簡單工廠承擔了太多的職責。DRY 原則提示咱們要清晰的劃清對象職責的界限。一個方法就是權力下放,將建立的知識移交給子類。知識的遞交意味着職責的轉移。
   
這樣作以後,咱們從新審視類之間的關係:核心工廠類再也不負責全部產品的建立,核心類的層次上升成爲一個抽象工廠角色,僅僅負責給出具體子類必須實現的接口,而不關係具體產品的建立細節。建立的知識由具體工廠擁有。而這時系統內也出現了一個平行的等級結構,產品家族的等級結構以及對應的工廠等級結構。
    簡單工廠把核心放在一個具體類上。Factory Method模式把核心放在抽象類,具體工廠類繼承了建立行爲。具體工廠都擁有相同的接口因此還有一個別名叫多態工廠模式。這是咱們關注點已經從實現轉移到了「接口」:關注動機而非實現,是基本的OO設計原則,將實現隱藏在接口以後其實是將對象的實現與它們的對象解耦了。從「依賴」的角度,系統中依賴的已經再也不是一個個具體的實現,而是一個抽象。這就是DIP原則高層模塊不該該依賴低層模塊,二者都應該依賴於抽象。這個原則隱含的意思是:對象之間只在概念層次存在耦合,在實現層次不能耦合!
     工廠方法模式的應用須要徹底遵照里氏替換原則 爲前提。即父類出現的地方可以替換成子類,工廠方法模式的應用才能成爲可能。
      咱們要添加一個新的產品,只要添加這個產品類和它的工廠類就能夠了。沒有必要修改Client和已經存在的工廠代碼。Factory Method徹底支持OCP原則


 抽象工廠模式

    抽象工廠向客戶端提供了一個接口,使得客戶端在不指定具體產品類型的時候就能夠建立產品族中的產品對象。這就是抽象工廠的用意。抽象工廠面的問題是多個等級產品等級結構的系統設計。抽象工廠和工廠方法模式最大的區別就在於後者只是針對一個產品等級結構;而抽象工廠則是面對多個等級結構。
      一樣出色的完成了把應用程序從特定的實現中解耦,工廠方法使用的方法是繼承,而抽象工廠使用的對象組合。抽象工廠提供的是一個產品家族的抽象類型,這個類型的子類完成了產品的建立。
       咱們在工廠方法模式中提到的OCP DIP LSP等原則的表述也適用於抽象工廠模式.

       我曾經在《視角的力量--再說OO 設計原則》一文中提到抽象出來高層策略是須要有必定穩定性的。抽象工廠做爲一個高層抽象若是它的接口發生變化,那麼影響是巨大的:全部的子類都要進行修改!這就要求抽象工廠的接口設計是高度抽象的!
 
總結:
  • 發現變化隔離封裝變化是動因,關閉修改打開擴展是限制
  • 簡單工廠很好地遵照了DRY原則,對OCP原則支持不足
  • 工廠方法模式徹底支持了OCP原則,使用的機制是繼承
  • 抽象工廠模式 工廠方法模式都徹底支持OCP原則
  • LSP原則是OCP成爲可能的重要原則,抽象工廠模式、工廠方法模式徹底遵照LSP
  • 依賴於抽象,一個類派生自具體類明顯違背了DIP原則
  • GRASP是另一個設計模式體系,它與GOF設計模式在不少地方是異曲同工,瞭解一下GRASP能夠幫助咱們思考 
相關文章
相關標籤/搜索