封裝變化之物件創建
在物件創建的程序中,經常會出現的一個問題就是通過顯示地指定一個類來創建物件,從而導致緊耦合,這是因為創建物件時指定類名將使你受特定實作的約束而不是特定介面的約束,這會使未來的變化更加復雜,要避免這種情況,就應該間接地創建物件,
這種緊耦合的問題很大程度是由new關鍵字帶來的,由于new的緊耦合出現,使得緊耦合的類很難獨立地被復用,因為它們之間是相互依賴的,并且緊耦合產生單塊的系統,要改變或者刪掉一個類,就必須要理解和改變其他許多類,這也是導致系統難以維護和移植的一個重要原因,
所以可以通過“物件創建”模式繞開new,從而避免在物件創建(new)程序中所導致的緊耦合(依賴具體的類),以此支持物件創建的穩定,
那么如何避免new呢?舉個例子!
public void fun1(){
//...
Product p = new Product(); //改為:Product p = productFactory.createProduct();
//...
}
這樣的方式就是通過一個工廠呼叫一個方法來創建相應的產品,但是可能大家又會產生一個問題,這樣操作雖然解決了Product的new操作,但是對于ProductFactory而言不是也需要通過new來產生嗎?
對于這個問題,我想是很多人在接觸到設計模式的時候都會去思考的問題,既然ProductFactory還是要用到new,那工廠類還有存在的必要嗎?這時,我們可以會想到兩種解決方式,一是將createProdyct()方法寫成靜態方法,這樣呼叫的時候自然不需要new了,二是通過注入的方式,比如在應用類當中通過setter或是構造方法傳入一個工廠類的物件,
對于靜態方法而言,簡單地說,即使是使用靜態方法,那Product p = ProductFactory.createProduct()這樣依然是一種緊耦合的方式,因為工廠類無法替換,和直接new出產品區別不大,
對于注入方式,大家更多的是疑惑,既然可以傳入一個工廠類物件,那為什么不直接傳入相應的產品,不是更簡單直接嗎?當然不是的,首先需要明白的是,工廠類的作用是作為一個籠子,這個籠子需要幫助我們束縛住 ‘未來的變化’ ,要知道一個產品的變化可能總是大于工廠的變化,在這種情況下,舉出一個最簡單的例子,你在編碼的程序中,可能會用到不只一個產品,那你就可能需要很多setter或者修改構造方法;但是如果這些產品都可以通過這個工廠來獲取,是不是就相當于用籠子關住了變化,使其在一個范圍中跳動,
在學習設計模式時,永遠要記住的一句話就是“設計模式是用來教會我們如何應對未來可能的變化”,如果你能夠確定自己的系統未來沒有變化,那自然用不到設計模式;或者你的系統未來全是變化,那也用不到設計模式,設計模式做的就是隔離穩定與變化,如果沒有穩定,那就用不到設計模式,
‘new’是一種硬編碼,究竟 ’硬‘ 在那里,同樣一個簡單的理由,如果未來構造方法發生變化或者說構造引數增加(減少),而在原始碼中有很多地方都是通過new來獲取實體物件,找到并修改原始碼將會是一項很大的作業,
在解決這樣的 “物件創建” 問題中就有工廠方法、抽象工廠、原型模式和建造者模式等相關設計模式,
工廠方法(Factory Method)
-
意圖
定義一個用于創建物件的介面,讓子類決定實體化哪一個類,FactoryMethod使得一個類的實體化延遲到其子類,
-
實體
Factory Method相對于簡單工廠而言,完全遵循了“不改代碼”的原則,但是其使用情形相比抽象工廠使用條件沒有那么高,因此可以說是使用最多的創建型模式之一了,
考慮這樣一個應用,它可以向用戶顯示多種檔案,比如word、pdf、txt等等,在這個框架中,首先,想到的可能就是應用簡單工廠模式,
public interface Document{ public void open(); public void close(); public void save(); // ...... } public class PdfDocument implements Document{ @Override public void open(){ //open pdfDocument code System.out.println("open pdf!"); } @Override public void close() { System.out.println("close pdf!"); } @Override public void save() { System.out.println("save pdf!"); } // ...... } public class TxtDocument implements Document{ //Txt實作代碼,同PdfDocument ...... } public class DocumentFactory{ public Document createDocument(String type){ if(type=="pdf"){ return new PdfDocument(); }else if(type=="txt"){ return new TxtDocument(); }else { return null; } } }//簡單工廠模式在客戶類當中的呼叫 public class Client { public static void main(String[] args) { DocumentFactory factory = new DocumentFactory(); Document pdfDocument = factory.createDocument("pdf"); pdfDocument.open(); pdfDocument.save(); pdfDocument.close(); Document txtDocument = factory.createDocument("txt"); txtDocument.open(); txtDocument.save(); txtDocument.close(); } }這樣簡單工廠模式,在不考慮未來新檔案型別的情況下,確實是一種不錯的實作方法,但是在后續的擴展程序當中,如果需要增加新的檔案類,就需要去修改
DocumentFactory中的createDocument()方法,增加新的類別,并且客戶還必須知道這些類別才能使用,為了應對這種情況,就出現了工廠方法,工廠方法就直接將工廠抽象出來,每個產品對應一個工廠,消除工廠模式中的條件分支結構(其實還有一種消除條件陳述句的模式,就是之前“組件協作”當中的策略模式),
//Document部分不變 public interface Document{ public void open(); public void close(); public void save(); ...... } public class PdfDocument implements Document{ public void open(){ //open pdfDocument code } // close 和 save ...... } public class TxtDocument implements Document{ //Txt實作代碼 ...... } //并且后續可以擴展新的檔案類 ......//修改factory部分如下 public interface DocumentFactory{ public Document createDocument(); } public class PdfDocumentFactory implements DocumentFactory { @Override public Document createDocument() { return new PdfDocument(); } } public class TxtDocumentFactory implements DocumentFactory { @Override public Document createDocument() { return new TxtDocument(); } } //如果后續有新的產品,直接再實作DocumentFactory,得到新的工廠 ......//呼叫程序可做如下修改: public class Client { public static void main(String[] args) { //利用多型性質,直接生成相應的factory子類 //消除了控制耦合 DocumentFactory factory = new PdfDocumentFactory(); Document pdfDocument = factory.createDocument(); pdfDocument.open(); pdfDocument.save(); pdfDocument.close(); factory = new TxtDocumentFactory(); Document txtDocument = factory.createDocument(); txtDocument.open(); txtDocument.save(); txtDocument.close(); } }有人可能會有疑問,這樣不是還沒完全消除new嗎?首先這里的客戶類已經到最高的呼叫層次了,這個程序當中是必然會有new的出現,不然怎樣進行程式呼叫呢?
我們所說的消除new的程序是指main與factory之間,產生的一個中間層次(如下面的App)中去消除new,
//這樣的代碼中,就消除了new的存在 //具體的注入程序可以由其他的形式完成,比如Spring中的DI public class App{ private DocumentFactory factory; public void setFactory(DocumentFactory factory) { this.factory = factory; } public void operateDoc(){ Document document = factory.createDocument(); document.open(); document.save(); document.close(); } } //main中的代碼是最高層次,也是變化最頻繁的層次,這里是不可能消除new的 public class Client { public static void main(String[] args) { DocumentFactory factory = new PdfDocumentFactory(); App app = new App(); app.setFactory(factory); app.operateDoc(); //同樣對于其他的工廠類也是可以采用同樣的方式呼叫, ...... } }這樣修改代碼的好處在那里呢?第一,顯而易見的就是完全實作了“開閉原則”的思想,擴展時不再需要去修改原始碼,第二,有些物件的創建程序可能比較復雜,因此如果直接在應用程式當中使用new或者其他形式創建很麻煩,通過工廠創建之后,就不再需要去關注那些復雜的創建程序,第三,通過new創建,始終是一種硬編碼的形式,如果在應用程式當中過多的使用這種方式,那么一旦某物件的創建方式發生改變,修改原始碼必然是很繁瑣的,
-
結構——類創建型模式

-
參與者
- Product(Document)
定義工廠方法中工廠創建的物件的介面,
-
ConcreteProduct(PdfDocument、TxtDocument)
實作Product的介面,
-
Creator(DocumentFactory)
宣告工廠方法——createProduct(),可以呼叫該方法回傳一個Product型別的物件,
-
ConcreteCreator(PdfDocumentFactory、TxtDocumentFactory)
重定義工廠方法以回傳具體的ConcreteProduct,
-
Client(客戶類)
使用工廠和產品,工廠方法模式中,客戶類也是一個重要的參與者,因為工廠方法主要的作用就是分離開客戶類與產品類之間的耦合關系,所以脫離客戶類去談工廠方法模式時,總會覺得差了些什么東西,無法完全體會到工廠方法模式的優勢,
-
適用性
在下列情況下可以使用Factory Method模式:
- 當一個類不知道它所必須創建的物件的類的時候,
- 當一個類希望由它的子類來指定它所創建的物件的時候,
- 當類將創建物件的職責委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一資訊區域化的時候,
簡單地說,就是使用程序中只需要宣告一個抽象工廠類的參考,具體呼叫那個工廠去生成那個物件,是由呼叫者去確定的,
-
相關模式
Abstract Factory經常用工廠方法來實作,抽象工廠創建產品的程序就可以使用工廠方法來完成,
工廠方法通常在Template Method中被呼叫,這一點在“組件協作”當中也提到過,
-
思考
- Creator的兩種實作情況,第一種情況,Creator只作為抽象層,也就是只宣告介面,不做任何的實作;這種情況就必須要子類來實作,第二種情況,Creator作為一個具體的實作類,而不是抽象類,這種情況下,Creator可以提供一個預設的實作介面,這樣即使沒有子類重寫它,客戶可以通過這樣一個預設的實作完成任務,
- 靈活運用工廠方法模式,作為一種創建類模式,在任何需要生成復雜物件的地方,都可以使用工廠方法模式,有一點需要注意的地方就是復雜物件適合使用工廠方法模式,而簡單物件,特別是只需要通過 new 就可以完成創建的物件(這也是為什么工廠方法講解用到的例子總是無法說服人的原因之一),無需使用工廠方法模式;因為使用工廠方法模式,就需要引入一個工廠類,會增加系統的復雜度,
抽象工廠(Abstract Factory)
-
意圖
提供一個創建一系列相關或相互依賴物件的介面,而無需指定他們具體的類,
-
實體
假定存在這樣一個服務層,該層當中需要做的就是訪問資料庫中的資料,并且執行一系列的相關操作,根據面向介面編程的思想,可以先作這樣一個代碼撰寫,
//對資料庫進行訪問的三個介面 //先建立連接,再執行相關操作,最后回傳相應結果 public interface DBConnection{} public interface DBCommand{} public interface DBDataReader{} //對于MySql,可以建立以下實作 public class MySqlDBConnection implements DBConnection{} public class MySqlDBCommand implements DBCommand{} public class MySqlDBDataReader implements DBDataReader{} //同樣對于Sql Server,Oricle也是這樣的實作 ......這樣的實作下,我們可以說是滿足了面向介面編程的一個思想;并且在實作中,我們可以為每個介面,按照工廠方法模式,為其創建一個工廠,
//工廠介面 public interface DBConnectionFactory{ public DBConnection createDBConnetion(); } public interface DBCommandFactory{ public DBCommand createDBCommand(); } public interface DBDataReaderFactory{ public DBDataReader createDBDataReader(); } //然后對于每個具體的資料庫,實作不同的具體工廠 //以MySql為例 public class MySqlDBConnetionFactory implements DBConnectionFactory { @Override public DBConnection createDBConnetion() { return new MySqlDBConnection(); } } public class MySqlDBCommandFactory implements DBCommandFactory { @Override public DBDBCommand createDBCommand() { return new MySqlDBCommand(); } } public class MySqlDataReaderFactory implements DataReaderFactory { @Override public DBDataReader createDataReader() { return new MySqlDataReader(); } } //剩下的Orcle,Sql Server也是如此 ......工廠模式方法的呼叫就不再演示,區別和工廠方法中的
Document例子中差別不大,對于這樣的實作,雖然我們很好的利用了工廠方法模式,但是也引入了工廠方法模式的一個弊端——大量的物件和類(本例當中,三個系列,每個系列三個產品,光產品就是9個子類;每個產品再對應一個工廠,一共就是18個子類),在使用的程序中,反而能夠明顯的感覺到系統復雜度不減反增,并且,
DBConnection、DBCommand和DBDataReader明顯是有著一定的關系的,換句話說,MySql建立的DBConnection是和MySqlDBCommand、MySqlDBDataReader一起使用的,如果出現MySqlDBConnection、OricleDBCommand、SqlServerDBDataReader這種組合肯定是無法正常執行的,這時抽象工廠的出現,就很好的解決了這樣的問題,//首先,具體的產品類不會發生變化,簡化的主要是工廠層次 //先抽象出抽象工廠,將產品系列的創建方法合并到一個介面中 public interface DBFactory{ public DBConnection createDBConnetion(); public DBCommand createDBCommand(); public DBDataReader createDBDataReader(); } //根據不同的具體工廠,創建具體的物件 public class MySqlDBFactory implements DBFactory { @Override public DBConnection createDBConnetion() { return new MySqlDBConnection(); } @Override public DBCommand createDBCommand() { return new MySqlDBCommand(); } @Override public DBDataReader createDBDataReader() { return new MySqlDBDataReader(); } } //Oricle,sql server的工廠,同樣如此 ......抽象工廠主要是對工廠層次的簡化,這樣修改下來,對比工廠方法模式,減少了2/3的工廠子類創建,只需要3個工廠(有多少個產品系列就有多少個工廠子類)就可以完成產品的創建,
這樣的一種創建工廠方式,不僅減少了工廠的數量,而且使得產品的一致性得以保證,它可以保證,一次只能使用同一個系列當中的物件,
public class Client { public static void main(String[] args) { DBFactory factory = new MySqlDBFactory(); App app = new App(); app.setFactory(factory); app.operate(); //同樣對于其他的工廠類也是可以采用同樣的方式呼叫, // ...... } } class App{ private DBFactory factory; public void setFactory(DBFactory factory) { this.factory = factory; } public void operate(){ DBConnection connection = factory.createDBConnetion(); DBCommand command = factory.createDBCommand(); DBDataReader reader = factory.createDBDataReader(); //執行相關操作 ..... } }這樣的應用程式代碼,在一定程度上就減少了工廠子類的數量,并且在
operate()中保證了產品系列的一致性,使得MysqlDBFactory生成的產品,只會是與MySql相關的, -
結構——物件創建型模式

-
參與者
-
AbstractFactory(DBFactory)
宣告一個創建抽象產品物件的操作介面,
-
ConcreteFactory(MySqlDBFactory)
實作創建具體產品物件的操作,
-
AbstractProduct(DBConnection、DBCommand、DBDataReader)
為一類產品物件宣告一個介面,
-
ConcreteProduct(MySqlDBConection、MySqlDBCommand、MySqlDBDataReader)
定義一個將被相應的具體工廠創建的產品物件,并實作抽象產品的相應介面,
-
Client
呼叫抽象工廠和抽象產品提供的介面,在創建者模式當中,客戶類也是重要的參與成員,因為對創建模式的理解容易混亂的點正是在客戶類中的呼叫程序 (new) 產生的,關于這個問題,已經在前面做過很多解釋了,不再多說,
-
-
適用性
以下情況可以使用AbstractFactory模式:
- 一個系統要獨立于它的產品的創建、組合和表示時,
- 一個系統要由多個產品系列中的一個來配置時,
- 當你要強調一系列相關的產品物件的設計以便進行聯合使用時,
- 當你提供一個產品類別庫,而只想顯示它們的介面而非實作時,
-
相關模式
Singleton:一個具體的工廠通常會是一個單件,因為在一個應用中,一般每個產品系列只需要一個具體工廠,
Factory Method:在Abstract Factory中,僅僅是宣告一個創建物件的介面,真正的創建程序是由具體工廠實作的,這時,可以為每一個方法對應的具體物件之間再定義一個工廠方法,但其問題就在于,這樣的做法就像是在工廠方法上再套上一層抽象工廠,從而又增加了系統的復雜度,
-
思考
- 難以支持新種類的產品 對于工廠模式而言,它的最大優點就在于保證了產品的一致性,但也正是如此,這就使得它的產品系列需要保持穩定,如果在后續的程序中出現新的產品,比如在實體當中需要增加一個新的功能系列,就需要去擴展
DBFactory介面,并且涉及到DBFactory及其子類的改變, - 定義可擴展的工廠 這是對于新種類產品創建靈活性的提高,但是不太安全;就是給創建 物件的操作增加一個引數,該引數來指定將被創建的物件種類,使用這種方式,抽象工廠就只需要一個“Create”方法和一個識別符號引數即可完成創建操作,但問題就在于,客戶需要完全了解所有的引數才能更好使用工廠創建自己所需要的物件,
- 難以支持新種類的產品 對于工廠模式而言,它的最大優點就在于保證了產品的一致性,但也正是如此,這就使得它的產品系列需要保持穩定,如果在后續的程序中出現新的產品,比如在實體當中需要增加一個新的功能系列,就需要去擴展
原型模式(Prototype)
-
意圖
用原型實體指定物件的創建種類,并且通過拷貝這些原型創建新的物件,
-
實體
Prototype模式,有點像是對工廠方法模式中產品與工廠的合并,怎么說呢?看下面的代碼:
//工廠方法模式中的產品類與工廠方法類 public interface Document{ public void open(); public void close(); public void save(); ...... } public interface DocumentFactory{ public Document createDocument(); }這是在Factory Method中使用的創建方式,而原型做的事就是,不再用工廠來進行創建,而是轉而克隆的方式,變成下面這樣:
//合并Document和DocumentFactory public abstract class Document implements Cloneable{ public void open(); public void close(); public void save(); ...... //相當于Factory中的createDocument(); public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } } public class PdfDocument implements Document{ @Override public void open(){ //open pdfDocument code System.out.println("open pdf!"); } @Override public void close() { System.out.println("close pdf!"); } @Override public void save() { System.out.println("save pdf!"); } //...... } //檔案類的實作與工廠方法中的一樣 ......那么在具體的客戶類當中就是通過這樣一種方式來進行呼叫:
public class App{ //在工廠方法模式當中,這里是documentFactory private Document prototype; public void setDoucument(Document document){ prototype = document; } public void useDocument(){ //documentFactory.createDocument(); Document doc = prototype.clone(); //然后使用prototype克隆出來的doc進行操作 doc.open(); ...... } } //在客戶類中呼叫表現 public class Client { public static void main(String[] args) { Document doc = new PdfDocument(); App app = new App(); app.setFactory(doc); app.useDocument(); //同樣對于其他的工廠類也是可以采用同樣的方式呼叫, //...... } }問題來了,為什么不直接用原型(prototype),而是要多一步克隆?解決這個問題,首先要明白的是,我們使用原型的目的不是將原型作為客戶類的一個屬性去使用,而是一個創建者,既然是一個創建者,那么在使用的程序中,就不只一個地方會用到同樣型別的物件;如果在不同的地方都直接使用原型,可能會在某個地方修改了原型的值,從而使得其他直接使用原型的方法出現不可預知的錯誤,
-
結構——物件創建型模式

-
參與者
-
Prototype(Document)
宣告一個克隆自身的介面,
-
ConcretePrototype(PdfDocument...)
繼承Prototype并實作克隆自身的介面,
-
Client
讓一個原型克隆自身從而創建一個新的物件,
-
-
適用性
-
當一個系統應該獨立于它的產品創建、構成和表示時,可以使用Prototype模式,
-
當要實體化的類是在運行時候指定時,比如動態裝載,
-
為了避免創建一個產品類平行的工廠類層次時,
-
當一個類的實體只能有幾種不同狀態組合中的一種時,建立相應數目的原型并克隆他們可以比每次用合適的狀態手工實體化該類更方便一些,
-
-
相關模式
Abstract Factory和Prototype在某種方面是相互競爭的,但是在某種情況下也是可以一起使用,比如,在抽象工廠中存盤一個被克隆的產品集合,在使用時,直接根據集合中的物件回傳相應的產品,
大量使用Composite(組合模式)和Decorator(裝飾器模式)的設計上也可以采用Protorype來減少Composite或Decorator物件的創建,
-
思考
- 減少了子類的構造,實體當中就可以看出,原型模式簡化了工廠方法模式中的工廠類,因此,減少了許多子類的創建,
- 資源優化,類初始化可能需要消化非常多的資源,這個資源包括資料、硬體資源等等,使用原型模式就可以減少這樣一個初始化程序,
- 深、淺拷貝的問題,對于java而言,淺拷貝實作 Cloneable,深拷貝是通過實作 Serializable 讀取二進制流,
建造者模式( Builder)
-
意圖
將一個復雜物件的構建與它的表示分離,使得同樣的構建程序可以有不同的表示,
-
實體
在游戲場景當中,尤其是3d場景中,必不可少就是建筑物,比如說房子,對房子的構建肯定不是一下全部構建完成的,而是會分成幾個部分,比如墻、窗戶、地板、房頂、門,一部分、一部分地去構建,
public abstract class House{ //房子屬性,紋理、材質... private Texture texture; private Material material; ...... //墻、窗戶、地板、房頂、門 public Wall buildWall(); public Window buildWindow(); public Floor buildFloor(); public Door buildDoor(); public Roof buildRoof(); //房子構建程序 public void buildHouse(){ buildFloor(); Wall[] walls = new Wall[4]; for(int i=0;i<walls.length;i++) walls[i] = buildWall(); Window window = buildWindow(); wall[1].setWindow(window); Door door = builDoor(); wall[2].setDoor(door); buildRoof(); } }這種構建方式,采用的明顯就是模板方法(Template Method),這種實作方式還可以根據不同的房子型別,實作具體的細節,
//石頭屋 public class StoneHouse extends House{ //具體實作細節 ....... } //茅草屋 public class ThatchedHouse extends House{ //具體實作細節 ....... }//按照模板主方法在客戶類中的呼叫形式表現: public class Client{ public static void main(String[] args){ //只需要生成一個相應物件即可在游戲場景中完成相應型別房子的創建 House house = new StoneHouse(); house.buildHouse(); //生成石頭屋 house = new ThatchedHouse(); house.buildHouse(); //生成茅草屋 } }這種實作有什么問題呢?類太臃腫了,對吧~這樣的實作程序,可以體現復用的思想,但是問題之一就在于所有的內容全部都放在了一個類中,體現不出單一職責和類的資訊與行為集中;這時就可以將創建程序分離出來,形成一個Builder,由這樣一個Builder來專門負責創建,
//Director public class House{ //房子屬性,紋理、材質... private Texture texture; private Material material; ...... //增加builder的引入 private HouseBuilder houseBuilder; public void setHouseBuilder(HouseBuilder hBuilder){ houseBuilder = hbuilder; } //房子構建程序 public void buildHouse(){ houseBuilder.buildFloor(); Wall[] walls = new Wall[4]; for(int i=0;i<walls.length;i++) walls[i] = houseBuilder.buildWall(); Window window = houseBuilder.buildWindow(); wall[1].setWindow(window); Door door = houseBuilder.builDoor(); wall[2].setDoor(door); houseBuilder.buildRoof(); } } //分離出來的builder public interface HouseBuilder{ //墻、窗戶、地板、房頂、門 public Wall buildWall(); public Window buildWindow(); public Floor buildFloor(); public Door buildDoor(); public Roof buildRoof(); } public class StoneHouseBuilder implements HouseBuilder{ //具體實作細節 ....... } public class ThatchedHouseBuilder implements HouseBuilder{ //具體實作細節 ....... }//修改過后,在客戶類中的呼叫形式表現: public class Client{ public static void main(String[] args){ //只需要生成一個相應物件即可在游戲場景中完成相應型別房子的創建 House house = new House(); HouseBuilder builder = new StoneHouseBuilder(); house.setHouseBuilder(builder); house.buildHouse(); builder = new ThatchedHouseBuilder(); //這個set程序可以運行時完成 house.setHouseBuilder(builder); house.buildHouse(); } }通過這樣一種方式,實作復雜物件構建與表示的分離,并且,對于不同的房子物件,如果房子其他引數沒有任何差別,就只需要傳入相應的builder即可,而不需要再生成各種各樣的子類(如
StoneHouse、ThatchedHouse),一旦生成物件,只需要修改其builder就可以馬上改變其物件表示,而不需要新生成物件,并且這種修改程序,是可以動態完成的,就如果Spring當中的依賴注入程序一樣,可以在運行時刻完成,而不一定是一開始就確定的
-
結構——物件創建型模式

-
參與者
-
Builder(HouseBuilder)
為創建一個Product物件的各個部件指定抽象介面,
-
ConcreteBuilder(StoneHouseBuilder、ThatchedHouseBuilder)
- 實作Builder的介面以構造各裝配該產品的各個部件,
- 定義并明確它所創建的表示,
-
Director(House)
構造一個使用builder的物件,
-
Product(Wall、Window...)
包含了定義組成部件的類以及被構造的復雜物件等,
-
-
適用性
Builder的適用情況:
- 當創建復雜物件的演算法應該獨立于該物件的組成部分,以及它們的裝配方式時,
- 當構造程序必須允許被構造的物件的不同的表示時,
Builder模式更多的是體現的一種思想,而不是具體的程序,這種思想就是,當一個類的資訊與行為過于臃腫時,也許可以采用Builder這種方式對類的資訊與行為進行重新劃分,從而使得類看起來更加的“輕” ,
-
相關模式
Abstract Factory和Builder都是對復雜物件的創建封裝,但二者的區別在于,Builder著重于一步一步構建一個復雜物件,而Abstract Factory著重于多個系列產品物件的創建,并且系列物件之間有著某種聯系,
Composite模式中物件通常情況下就是用Builder生成的,
-
思考
- 可以改變產品的內部表示 Builder物件提供給Director一個構造產品物件的內部介面,從而使得產品的表示和內部結構得以隱藏,因此,在構建程序中,只需要替換不同的Builder就可以得到不同的表示,
- Builder中的方法可以預設為空 這樣在具體的實作程序中,客戶可以只實作他們感興趣的操作,這種方式其實在很多模式中都可以應用,其最主要的思想就是能用默認配置當然是最好的,
公眾號:良許Linux
有識訓?希望老鐵們來個三連擊,給更多的人看到這篇文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/38434.html
標籤:Linux
上一篇:006.Nginx訪問控制
