Java面試通關手冊(Java學習指南,歡迎Star,會一直完善下去,歡迎建議和指導):github.com/Snailclimb/…html
歷史回顧:java
深刻理解單例模式git
歷史文章推薦:github
面試中關於Java虛擬機(jvm)的問題看這篇就夠了設計模式
[TOC]服務器
先來看一下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)簡單工廠(Simple Factory)模式,又稱靜態工廠方法模式(Static Factory Method Pattern)。
(2)工廠方法(Factory Method)模式,又稱多態性工廠(Polymorphic Factory)模式或虛擬構造子(Virtual Constructor)模式;
(3)抽象工廠(Abstract Factory)模式,又稱工具箱(Kit 或Toolkit)模式。
舉兩個比較常見的例子(我暫時能夠準確想到的,固然還有不少不少):
(1)Spring中經過getBean("xxx")獲取Bean;
(2) Java消息服務JMS中(下面以消息隊列ActiveMQ爲例子)
關於消息隊列ActiveMQ的使用能夠查看:消息隊列ActiveMQ的使用詳解
// 一、建立一個鏈接工廠對象,須要指定服務的ip及端口。
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.155:61616");
// 二、使用工廠對象建立一個Connection對象。
Connection connection = connectionFactory.createConnection();
複製代碼
(1) 解耦 :把對象的建立和使用的過程分開
(2)下降代碼重複: 若是建立某個對象的過程都很複雜,須要必定的代碼量,並且不少地方都要用到,那麼就會有不少的重複代碼。
(3) 下降維護成本 :因爲建立過程都由工廠統一管理,因此發生業務邏輯變化,不須要找到全部須要建立某個對象的地方去逐個修正,只須要在工廠裏修改便可,下降維護成本。
關於工廠模式的做用,Mark一篇文章:blog.csdn.net/lovelion/ar…
嚴格的說,簡單工廠模式並非23種經常使用的設計模式之一,它只算工廠模式的一個特殊實現。簡單工廠模式在實際中的應用相對於其餘2個工廠模式用的仍是相對少得多,由於它只適應不少簡單的狀況。
最重要的是它違背了咱們在概述中說的 開放-封閉原則 (雖然能夠經過反射的機制來避免,後面咱們會介紹到) 。由於每次你要新添加一個功能,都須要在生switch-case 語句(或者if-else 語句)中去修改代碼,添加分支條件。
(1)須要建立的對象較少。
(2)客戶端不關心對象的建立過程。
建立一個能夠繪製不一樣形狀的繪圖工具,能夠繪製圓形,正方形,三角形,每一個圖形都會有一個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()方法,這很明顯不符合 開放-封閉原則 。
將工廠類改成下面的形式:
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();
}
}
複製代碼
這種方式的雖然符合了 開放-關閉原則 ,可是每一次傳入的都是產品類的所有路徑,這樣比較麻煩。若是須要改善的話能夠經過 反射+配置文件 的形式來改善,這種方式使用的也是比較多的。
工廠方法模式應該是在工廠模式家族中是用的最多模式,通常項目中存在最多的就是這個模式。
工廠方法模式是簡單工廠的僅一步深化, 在工廠方法模式中,咱們再也不提供一個統一的工廠類來建立全部的對象,而是針對不一樣的對象提供不一樣的工廠。也就是說 每一個對象都有一個與之對應的工廠 。
上面簡單工廠例子中的圖形接口以及相關圖像實現類不變。咱們只須要增長一個工廠接口以及實現這個接口的工廠類便可。
(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 Circle
複製代碼
在工廠方法模式中,其實咱們有一個潛在乎識的意識。那就是咱們生產的都是同一類產品。抽象工廠模式是工廠方法的僅一步深化,在這個模式中的工廠類不僅僅能夠建立一種產品,而是能夠建立一組產品。
抽象工廠應該是比較最難理解的一個工廠模式了。
。
抽象工廠是生產一整套有產品的(至少要生產兩個產品),這些產品必須相互是有關係或有依賴的,而工廠方法中的工廠是生產單一產品的工廠。
不知道你們玩過穿越火線或者吃雞這類遊戲了嗎,遊戲中存在各類槍。咱們假設如今存在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學習資源)
最後,就是使用阿里雲服務器一段時間後,感受阿里雲真的很不錯,就申請作了阿里雲大使,而後這是個人優惠券地址.