摘要:工廠模式的分類簡單工廠模式,又稱靜態工廠方法模式。工廠方法模式,又稱多態性工廠模式或虛擬構造子模式抽象工廠模式,又稱工具箱或模式。具體產品角色抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。
Java面試通關手冊(Java學習指南,歡迎Star,會一直完善下去,歡迎建議和指導):https://github.com/Snailclimb/Java_Guide
歷史回顧:
深入理解單例模式
歷史文章推薦:
分布式系統的經典基礎理論
可能是最漂亮的Spring事務管理詳解
面試中關于Java虛擬機(jvm)的問題看這篇就夠了
[TOC]
一 工廠模式介紹 1.1 工廠模式的定義先來看一下GOF為工廠模式的定義:
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”(在基類中定義創建對象的一個接口,讓子類決定實例化哪個類。工廠方法讓一個類的實例化延遲到子類中進行。)1.2 工廠模式的分類:
(1)簡單工廠(Simple Factory)模式,又稱靜態工廠方法模式(Static Factory Method Pattern)。
(2)工廠方法(Factory Method)模式,又稱多態性工廠(Polymorphic Factory)模式或虛擬構造子(Virtual Constructor)模式;
(3)抽象工廠(Abstract Factory)模式,又稱工具箱(Kit 或Toolkit)模式。
1.3 在開源框架中的使用舉兩個比較常見的例子(我暫時可以準確想到的,當然還有很多很多):
(1)Spring中通過getBean("xxx")獲取Bean;
(2) Java消息服務JMS中(下面以消息隊列ActiveMQ為例子)
關于消息隊列ActiveMQ的使用可以查看:消息隊列ActiveMQ的使用詳解
// 1、創建一個連接工廠對象,需要指定服務的ip及端口。 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.155:61616"); // 2、使用工廠對象創建一個Connection對象。 Connection connection = connectionFactory.createConnection();1.4 為什么要用工廠模式
(1) 解耦 :把對象的創建和使用的過程分開
(2)降低代碼重復: 如果創建某個對象的過程都很復雜,需要一定的代碼量,而且很多地方都要用到,那么就會有很多的重復代碼。
(3) 降低維護成本 :由于創建過程都由工廠統一管理,所以發生業務邏輯變化,不需要找到所有需要創建對象B的地方去逐個修正,只需要在工廠里修改即可,降低維護成本。
關于工廠模式的作用,Mark一篇文章:https://blog.csdn.net/lovelion/article/details/7523392
二 簡單工廠模式 2.1 介紹嚴格的說,簡單工廠模式并不是23種常用的設計模式之一,它只算工廠模式的一個特殊實現。簡單工廠模式在實際中的應用相對于其他2個工廠模式用的還是相對少得多,因為它只適應很多簡單的情況。
最重要的是它違背了我們在概述中說的 開放-封閉原則 (雖然可以通過反射的機制來避免,后面我們會介紹到) 。因為每次你要新添加一個功能,都需要在生switch-case 語句(或者if-else 語句)中去修改代碼,添加分支條件。
2.2 適用場景(1)需要創建的對象較少。
(2)客戶端不關心對象的創建過程。
2.3 簡單工廠模式角色分配:工廠(Factory)角色 :簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類可以被外界直接調用,創建所需的產品對象。
抽象產品(Product)角色 :簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口。
具體產品(Concrete Product)角色:簡單工廠模式的創建目標,所有創建的對象都是充當這個角色的某個具體類的實例。
2.4 簡單工廠實例創建一個可以繪制不同形狀的繪圖工具,可以繪制圓形,正方形,三角形,每個圖形都會有一個draw()方法用于繪圖.
(1)創建Shape接口
public interface Shape { void draw(); }
(2)創建實現該接口的具體圖形類
圓形
public class Circle implements Shape { public Circle() { System.out.println("Circle"); } @Override public void draw() { System.out.println("Draw Circle"); } }
長方形
public class Rectangle implements Shape { public Rectangle() { System.out.println("Rectangle"); } @Override public void draw() { System.out.println("Draw Rectangle"); } }
正方形
public class Square implements Shape { public Square() { System.out.println("Square"); } @Override public void draw() { System.out.println("Draw Square"); } }
(3)創建工廠類:
public class ShapeFactory { // 使用 getShape 方法獲取形狀類型的對象 public static Shape getShape(String shapeType) { if (shapeType == null) { return null; } if (shapeType.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("RECTANGLE")) { return new Rectangle(); } else if (shapeType.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } }
(4)測試方法:
public class Test { public static void main(String[] args) { // 獲取 Circle 的對象,并調用它的 draw 方法 Shape circle = ShapeFactory.getShape("CIRCLE"); circle.draw(); // 獲取 Rectangle 的對象,并調用它的 draw 方法 Shape rectangle = ShapeFactory.getShape("RECTANGLE"); rectangle.draw(); // 獲取 Square 的對象,并調用它的 draw 方法 Shape square = ShapeFactory.getShape("SQUARE"); square.draw(); } }
輸出結果:
Circle Draw Circle Rectangle Draw Rectangle Square Draw Square
這樣的實現有個問題,如果我們新增產品類的話,就需要修改工廠類中的getShape()方法,這很明顯不符合 開放-封閉原則 。
2.5 使用反射機制改善簡單工廠將工廠類改為下面的形式:
package factory_pattern; /** * 利用反射解決簡單工廠每次增加新了產品類都要修改產品工廠的弊端 * * @author Administrator * */ public class ShapeFactory2 { public static Object getClass(Class extends Shape> clazz) { Object obj = null; try { obj = Class.forName(clazz.getName()).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return obj; } }
測試方法:
package factory_pattern; public class Test2 { public static void main(String[] args) { Circle circle = (Circle) ShapeFactory2.getClass(factory_pattern.Circle.class); circle.draw(); Rectangle rectangle = (Rectangle) ShapeFactory2.getClass(factory_pattern.Rectangle.class); rectangle.draw(); Square square = (Square) ShapeFactory2.getClass(factory_pattern.Square.class); square.draw(); } }
這種方式的雖然符合了 開放-關閉原則 ,但是每一次傳入的都是產品類的全部路徑,這樣比較麻煩。如果需要改善的話可以通過 反射+配置文件 的形式來改善,這種方式使用的也是比較多的。
3 工廠方法模式 3.1 介紹工廠方法模式應該是在工廠模式家族中是用的最多模式,一般項目中存在最多的就是這個模式。
工廠方法模式是簡單工廠的僅一步深化, 在工廠方法模式中,我們不再提供一個統一的工廠類來創建所有的對象,而是針對不同的對象提供不同的工廠。也就是說 每個對象都有一個與之對應的工廠 。
3.2 適用場景一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏
將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無需關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
3.3 工廠方法模式角色分配:抽象工廠(Abstract Factory)角色:是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。
具體工廠(Concrete Factory)角色 :這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創建某一種產品對象。
抽象產品(AbstractProduct)角色 :工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
具體產品(Concrete Product)角色 :這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應
3.4 工廠方法模式實例上面簡單工廠例子中的圖形接口以及相關圖像實現類不變。我們只需要增加一個工廠接口以及實現這個接口的工廠類即可。
(1)增加一個工廠接口:
public interface Factory { public Shape getShape(); }
(2)增加相關工廠類:
圓形工廠類
public class CircleFactory implements Factory { @Override public Shape getShape() { // TODO Auto-generated method stub return new Circle(); } }
長方形工廠類
public class RectangleFactory implements Factory{ @Override public Shape getShape() { // TODO Auto-generated method stub return new Rectangle(); } }
圓形工廠類
public class SquareFactory implements Factory{ @Override public Shape getShape() { // TODO Auto-generated method stub return new Square(); } }
(3)測試:
public class Test { public static void main(String[] args) { Factory circlefactory = new CircleFactory(); Shape circle = circlefactory.getShape(); circle.draw(); } }
輸出結果:
Circle Draw Circle4 抽象工廠模式 4.1 介紹
在工廠方法模式中,其實我們有一個潛在意識的意識。那就是我們生產的都是同一類產品。抽象工廠模式是工廠方法的僅一步深化,在這個模式中的工廠類不單單可以創建一種產品,而是可以創建一組產品。
抽象工廠應該是比較最難理解的一個工廠模式了。
4.2 適用場景和工廠方法一樣客戶端不需要知道它所創建的對象的類。
需要一組對象共同完成某種功能時,并且可能存在多組對象完成不同功能的情況。(同屬于同一個產品族的產品)
系統結構穩定,不會頻繁的增加對象。(因為一旦增加就需要修改原有代碼,不符合開閉原則)
4.3 抽象工廠方法模式角色分配:抽象工廠(AbstractFactory)角色 :是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。
具體工廠類(ConreteFactory)角色 :這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創建某一種產品對象。
抽象產品(Abstract Product)角色 :工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
具體產品(Concrete Product)角色 :抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。在抽象工廠中創建的產品屬于同一產品族,這不同于工廠模式中的工廠只創建單一產品,我后面也會詳解介紹到。
。
4.4 抽象工廠的工廠和工廠方法中的工廠有什么區別呢?抽象工廠是生產一整套有產品的(至少要生產兩個產品),這些產品必須相互是有關系或有依賴的,而工廠方法中的工廠是生產單一產品的工廠。
4.5 抽象工廠模式實例不知道大家玩過穿越火線或者吃雞這類游戲了嗎,游戲中存在各種槍。我們假設現在存在AK、M4A1兩類槍,每一種槍對應一種子彈。我們現在這樣考慮生產AK的工廠可以順便生產AK使用的子彈,生產M4A1的工廠可以順便生產M4A1使用的子彈。(AK工廠生產AK系列產品包括子彈啊,AK槍的類型啊這些,M4A1工廠同理)
(1)創建相關接口:
槍
public interface Gun { public void shooting(); }
子彈
public interface Bullet { public void load(); }
(2)創建接口對應實現類:
AK類
public class AK implements Gun{ @Override public void shooting() { System.out.println("shooting with AK"); } }
M4A1類
public class M4A1 implements Gun { @Override public void shooting() { System.out.println("shooting with M4A1"); } }
AK子彈類
public class AK_Bullet implements Bullet { @Override public void load() { System.out.println("Load bullets with AK"); } }
M4A1子彈類
public class M4A1 _Bullet implements Bullet { @Override public void load() { System.out.println("Load bullets with M4A1"); } }
(3)創建工廠接口
public interface Factory { public Gun produceGun(); public Bullet produceBullet(); }
(4)創建具體工廠
生產AK和AK子彈的工廠
public class AK_Factory implements Factory{ @Override public Gun produceGun() { return new AK(); } @Override public Bullet produceBullet() { return new AK_Bullet(); } }
生產M4A1和M4A1子彈的工廠
public class M4A1_Factory implements Factory{ @Override public Gun produceGun() { return new M4A1(); } @Override public Bullet produceBullet() { return new M4A1_Bullet(); } }
(5)測試
public class Test { public static void main(String[] args) { Factory factory; Gun gun; Bullet bullet; factory =new AK_Factory(); bullet=factory.produceBullet(); bullet.load(); gun=factory.produceGun(); gun.shooting(); } }
輸出結果:
Load bullets with AK shooting with AK
我是Snailclimb,一個以架構師為5年之內目標的小小白。 歡迎關注我的微信公眾號:"Java面試通關手冊"(一個有溫度的微信公眾號,期待與你共同進步~~~堅持原創,分享美文,分享各種Java學習資源)
最后,就是使用阿里云服務器一段時間后,感覺阿里云真的很不錯,就申請做了阿里云大使,然后這是我的優惠券地址.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69537.html
摘要:本文一大半內容都是通過舉例來讓讀者去理解什么是控制反轉和依賴注入,通過理解這些概念,來更加深入。這種由外部負責其依賴需求的行為,我們可以稱其為控制反轉。工廠模式,依賴轉移當然,實現控制反轉的方法有幾種。 容器,字面上理解就是裝東西的東西。常見的變量、對象屬性等都可以算是容器。一個容器能夠裝什么,全部取決于你對該容器的定義。當然,有這樣一種容器,它存放的不是文本、數值,而是對象、對象的描...
摘要:而建造者模式則是要求按照指定的藍圖建造產品,它的主要目的是通過組裝零配件而產生一個新產品。最后通過一個套餐實例,介紹了建造者模式在實例中的基本使用手段。 歷史文章回顧: 設計模式專欄 深入理解單例模式 深入理解工廠模式 歷史優質文章推薦: 分布式系統的經典基礎理論 可能是最漂亮的Spring事務管理詳解 面試中關于Java虛擬機(jvm)的問題看這篇就夠了 無論是在現實世界中還是在軟件...
摘要:在設計模式中,所有的設計模式都遵循這一原則。其實就是說在應用程序中,所有的類如果使用或依賴于其他的類,則應該依賴這些其他類的抽象類,而不是這些其他類的具體類。使用設計模式是為了可重用代碼讓代碼更容易被他人理解保證代碼可靠性。 這是劉意老師的JAVA基礎教程的筆記講的賊好,附上傳送門 傳智風清揚-超全面的Java基礎 一、面向對象思想設計原則 1.單一職責原則 其實就是開發人員經常說的高...
摘要:相對于工廠模式,抽象工廠模式生產的對象更加具體,也更加豐富,但相對編碼也更加復雜。具體的抽象工廠模式的實現大家可以參考菜鳥教程。知道了工廠模式和抽象工廠模式的區別,請大家使用的時候應該根據具體的情況進行選擇。 大家好,今天給大家分享一些Spring的學習心得,在講Spring之前,先和大家分享Spring中核心的設計模式。 工廠模式 在聊概念之前我先問問大家:什么是工廠? 這個很簡單,...
閱讀 3244·2021-11-11 11:00
閱讀 2565·2019-08-29 11:23
閱讀 1441·2019-08-29 10:58
閱讀 2323·2019-08-29 10:58
閱讀 2952·2019-08-23 18:26
閱讀 2507·2019-08-23 18:18
閱讀 2038·2019-08-23 16:53
閱讀 3411·2019-08-23 13:13