Spring Boot中使用注解实现简单工厂模式
前言
從設(shè)計模式的類型上來說,簡單工廠模式是屬于創(chuàng)建型模式,又叫靜態(tài)工廠模式(Simple Factory Pattern),但不屬于23種GOF設(shè)計模式之一。簡單工廠模式是由一個工廠對象決定創(chuàng)建出接口哪一種實現(xiàn)類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現(xiàn)。
在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創(chuàng)建其他類的實例,被創(chuàng)建的實例通常都具有共同的父類。
簡單工廠模式只需要向工廠類傳入一個正確的參數(shù),就可以獲取所需要的對象,而無需知道其實現(xiàn)過程。
簡單工廠模式是在什么場景下使用呢?這里簡單的枚舉幾個使用場景:
1、日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠程服務(wù)器等,用戶可以選擇記錄日志到什么地方;
2、保險產(chǎn)品配置:保險產(chǎn)品往往有很多賠付等級,每個等級對應(yīng)不同的保額和賠付金額;
3、設(shè)計一個連接服務(wù)器的框架,需要三個協(xié)議,"POP3"、"IMAP"、"HTTP",可以把這三個作為產(chǎn)品類,共同實現(xiàn)一個接口。
定義中最重要的一句話就是,由一個工廠對象決定創(chuàng)建出哪一種實現(xiàn)類的實例。在文章《Spring注解之@Autowired:注入Arrays, Collections, and Maps》中,小編介紹了Spring Boot如何把某些接口實現(xiàn)類的Bean注入到Map和List等集合中,方便應(yīng)用的時候直接讀取需要的bean。結(jié)合@Autowired可以自動注入指定接口實現(xiàn)類到Map中,介紹簡單工廠模式的一個實現(xiàn)策略。
簡單工廠模式實踐
我們將創(chuàng)建一個 Shape 接口和實現(xiàn) Shape 接口的實體類。下一步是定義工廠類 ShapeFactory。在controller FactoryPatternDemo 中,我們演示使用 ShapeFactory 來獲取 Shape 對象。它將向 ShapeFactory 傳遞信息(circle/rectangle/square),以便獲取它所需對象的類型。
新增接口類Shape:
/**
* 定義bean接口
*/
public interface Shape {
void draw();
}
創(chuàng)建Shape的三個實現(xiàn)類,并且都添加注解@Service,將其注冊為Spring Bean。
@Service
public class Rectangle implements Shape { @Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
=========== 我是分割線 =============
@Service
public class Square implements Shape { @Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
=========== 我是分割線 =============
@Service
public class Circle implements Shape { @Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
實現(xiàn)方法一:基于新建對象實現(xiàn)
茲創(chuàng)建一個工廠類,根據(jù)調(diào)用者的不同,創(chuàng)建不同的實現(xiàn)類并返回。而如果碰到不合法的請求參數(shù),則會返回null。
/**
* 簡單工廠類,通過新建對象實現(xiàn)
* 不添加Spring注解,調(diào)用的時候直接new
*/
public class ShapeFactory {
/**
* 使用 getShape 方法獲取幾何圖形類型的對象
*/
public static Shape getShape(String shapeType) {
if ("circle".equalsIgnoreCase(shapeType)) {
return new Circle();
} else if ("rectangle".equalsIgnoreCase(shapeType)) {
return new Rectangle();
} else if ("square".equalsIgnoreCase(shapeType)) {
return new Square();
}
return null;
}
}
實現(xiàn)方法二:基于spring注解實現(xiàn)
下面新增一個類ShapeBeanFactory,通過@Autowired注解把bean注入map后,由變量map替換工廠類,實現(xiàn)簡單工廠模式。
/**
* 簡單工廠類,通過 Spring注解 @Autowired 和 @Service 實現(xiàn)
*/
@Component // 添加Spring注解
public class ShapeBeanFactory { @Autowired
private Map<String, Shape> shapeMap; public Shape getShape(String shapeType) {
Shape bean1 = shapeMap.get(shapeType);
System.out.println(bean1);
return bean1;
} }
通過對比兩種實現(xiàn)方案可以發(fā)現(xiàn),使用Spring注解的方式更加簡潔,避開了 if else 分支。
客戶端調(diào)用工廠類
創(chuàng)建一個controller,命名為FactoryPatternDemo,并把兩種實現(xiàn)方案封裝為不同的私有方法。客戶端調(diào)用工廠類,傳入幾何圖形類型參數(shù)獲取幾何圖形對象并調(diào)用該對象的draw方法:
@GetMapping("/drawMyShape")
public String drawMyShape(){
shapeFactoryDraw();
shapeBeanFactoryDraw();
return "成功";
}
private void shapeFactoryDraw() {
System.out.println("======= shapeFactory =======");
//獲取 Circle 的對象,并調(diào)用它的 draw 方法
Shape shapeInterface1 = ShapeFactory.getShape("circle");
//調(diào)用 Circle 的 draw 方法
shapeInterface1.draw();
Shape shapeInterface2 = ShapeFactory.getShape("rectangle");
shapeInterface2.draw();
}
@Autowired
private ShapeBeanFactory factory; // 使用注解注入
private void shapeBeanFactoryDraw() {
System.out.println("======= 實現(xiàn)二 shapeBeanFactory =======");
Shape shapeInterface1 = factory.getShape("circle");
shapeInterface1.draw();
Shape shapeInterface2 = factory.getShape("square");
shapeInterface2.draw();
}
客戶端請求draw函數(shù),控制臺輸出結(jié)果如下,說明對工廠類重構(gòu)成功。
======= shapeFactory =======
Inside Circle::draw() method.
Inside Rectangle::draw() method.
======= 實現(xiàn)二 shapeBeanFactory =======
com.eg.wiener.service.impl.shape.Circle@3a0aa6f6
Inside Circle::draw() method.
com.eg.wiener.service.impl.shape.Square@6d48c8f9
Inside Square::draw() method.
優(yōu)缺點和適用場景
優(yōu)點
工廠類是整個模式的關(guān)鍵。包含了必要的邏輯判斷,根據(jù)外界給定的信息,決定究竟應(yīng)該創(chuàng)建哪個具體類的對象。通過使用工廠類,外界可以從直接創(chuàng)建具體產(chǎn)品對象的尷尬局面擺脫出來,僅僅需要負責“消費”對象就可以了,而不必管這些對象究竟如何創(chuàng)建及如何組織的,只需要知道具體產(chǎn)品類所對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名,通過簡單工廠模式可以減少使用者的記憶量。明確了各自的職責和權(quán)利,有利于整個軟件體系結(jié)構(gòu)的優(yōu)化。
通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類,在一定程度上提高了系統(tǒng)的靈活性。
缺點
由于工廠類集中了所有實例的創(chuàng)建邏輯,違反了高內(nèi)聚責任分配原則,將全部創(chuàng)建邏輯集中到了一個工廠類中;它所能創(chuàng)建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。
當系統(tǒng)中的具體產(chǎn)品類不斷增多時候,可能會出現(xiàn)要求工廠類根據(jù)不同條件創(chuàng)建不同實例的需求。這種對條件和具體產(chǎn)品類型的判斷交錯在一起,很難避免模塊功能的蔓延,對系統(tǒng)的維護和擴展非常不利;
違背開閉原則。對于上面兩種簡單工廠模式的實現(xiàn)方法,如果我們要添加新的 幾何圖形,勢必要改動 ShapeFactory的代碼,那這是不是違反開閉原則呢?實際上,如果不需要頻繁地添加新的幾何圖形實現(xiàn)類,只是偶爾修改一下代碼,稍微不符合開閉原則,但權(quán)衡擴展性和可讀性,這樣的代碼實現(xiàn)在大多數(shù)情況下,也是可以接受的。這是第一種實現(xiàn)方案的瑕疵,但是,第二種實現(xiàn)方案就沒有違背開閉原則,完全由Spring IOC容器管理Bean,彰顯了Spring IOC容器的強大之處。
適用場景
在以下場景適合使用簡單工廠模式:
工廠類負責創(chuàng)建的對象比較少:由于創(chuàng)建的對象較少,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜。
客戶端只知道傳入創(chuàng)建工廠類所需的參數(shù),對于如何創(chuàng)建對象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細節(jié),甚至連類名都不需要記住,只需要知道類型所對應(yīng)的參數(shù)。
Reference
https://www.runoob.com/design-pattern/factory-pattern.html
http://www.cnblogs.com/java-my-life/archive/2012/03/22/2412308.html
https://www.jianshu.com/p/5cb52d84bd6d
總結(jié)
以上是生活随笔為你收集整理的Spring Boot中使用注解实现简单工厂模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django Web应用开发实战第四章
- 下一篇: 光影精灵4怎么下软件 如何下载光影精灵4