一、簡單工廠模式
簡單工廠模式(Simple Factory Pattern)由一個工廠對象決定創建哪一種產品類的實例,簡單工廠模式適用於工廠類負責創建對象較少的情況,且客戶端只需要傳入工廠類的參數,對於如何創建對象不關心。
public interface IBlog { //寫隨筆 public void write(); }
public class JavaBlog implements IBlog { @Override public void write() { System.out.println("寫java隨筆"); } }
public class WriteBlog { public static void main(String[] args) { IBlog blog = new JavaBlog(); blog.write(); } }
上述代碼中,父類 IBlog 指向子類JavaBlog 的引用,應用層需要依賴JavaBlog,如果增加PythonBlog等等更多的課程,客戶端就會越來越臃腫。因此要把依賴減弱,把創建細節隱藏。現在我們用簡單工廠優化:
public class BlogFactory { public IBlog create(Class<? extends IBlog> clazz) { if (null != clazz) { try { return clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } } return null; } }
客戶端改變:
public static void main(String[] args) { BlogFactory blogFactory = new BlogFactory(); IBlog blog = blogFactory.create(JavaBlog.class); blog.write(); }
簡單工廠模式在JDK中很常見,如Calender類(感興趣去看源碼),還有logback,LoggerFactory中有很多重載的方法getLogger()。但是簡單工廠也有缺點:工廠類的職責相對過重,不易於擴展過於復雜的產品結構。
二、工廠方法模式
工廠方法模式(Factory Method Pattern)是指定義一個創建對象的接口,但讓實現這個接口的類來決定實例化哪個類,工廠方法模式讓類的實例化推遲到子類中進行。在工廠方法模式中,用戶只需要關心所需產品對應工廠,無須關心創建的細節,而且加入新產品時符合開閉原則。
工廠方法模式主要解決產品擴展問題。在簡單工廠模式中,隨着產品的增多,如果不同語言書寫隨筆的邏輯各不相同,工廠職責越來越多,那工廠里面就會亂搞一氣,狗屁不通。根據單一職責原則,我們將只能進行拆分,不同工廠做不同事,Java隨筆由Java工廠創建,Python隨筆由Python工廠創建,對工廠本身進行抽象。
先創建工廠類:
public interface IBlogFactory { IBlog create(); }
再創建對應工廠:
public class JavaBlogFactory implements IBlogFactory { @Override public IBlog create() { return new JavaBlog(); } } public class PythonBlogFactory implements IBlogFactory { @Override public IBlog create() { return new PythonBlog(); } }
客戶端:
public class CreateBlog { public static void main(String[] args) { IBlogFactory factory = new PythonBlogFactory(); IBlog blog = factory.create(); blog.write(); factory = new JavaBlogFactory(); blog = factory.create(); blog.write(); } }
總結來說就是:不同工廠抽象出一個工廠頭子,不同的工廠創建不同的實例。
工廠方法模式適用於以下場景:
1.創建對象需要大量重復代碼。
2.客戶端(應用層)不依賴於產品類實例如何被創建、如何被實現等細節。
3.一個類通過其子類來指定創建哪個對象。
缺點:
1.類的個數容易過多,增加復雜度。
2.增加了系統的抽象性和理解難度。
三、抽象工廠
抽象工廠(Abstract Factory Pattern)提供一個黃健一系列相關或相互依賴對象的接口,無需指定具體類。客戶端(應用層)不依賴於產品類實例如何被創建、如何被實現等細節,強調的是一系列相關得產品對象(屬於同一產品族)一起使用創建對象需要大量重復代碼。需要提供一個產品類的庫,所有產品以同樣接口出現,從而是客戶端不依賴於具體實現。
產品族:同一家的不同產品,比如小米,華為,蘋果;
產品等級:不同種類的產品,比如 手機,電視,電腦。
工廠要做的就是生產我們牌子的所有產品。以博客為例,java分類的博客有隨筆、文章、日記等。
首先創建文章和日記的抽象接口:
public interface IDocument { void write(); } public interface INote { void make(); }
再創建抽象工廠:
public interface BlogFactory { INote createNote(); IDocument createDocument(); }
實現Java文章和日記:
public class JavaDocument implements IDocument { @Override public void write() { System.out.println("寫Java文章"); } } public class JavaNote implements INote { @Override public void make() { System.out.println("寫Java筆記"); } }
實現Java產品族具體工廠:
public class JavaBlogFactory implements BlogFactory { @Override public INote createNote() { return new JavaNote(); } @Override public IDocument createDocument() { return new JavaDocument(); } }
實現Python文章和日記、實現Python具體工廠參考Java的。
客戶端調用:
public class BlogTest { public static void main(String[] args) { JavaBlogFactory factory = new JavaBlogFactory(); factory.createDocument().write(); factory.createNote().make(); } }
上述代碼描述了兩個產品族的工廠,如果想要擴展產品等級(就是再加點評啥的),要調整抽象工廠、具體工廠。由此可見抽象工廠模式的缺點:
1.規定所有可能被創建的產品集合,產品族(Java系列)中擴展新產品很困難,需要修改抽象工廠及實現;
2.增加系統抽象性和理解難度;
我們可以利用工廠模式創建好數據源連接池並放到容器中,業務需要時再取出。就避免了用一次創建一次的尷尬。