工廠模式是JAVA中
最常用的設計模式之一
,使用工廠模式後,創建對象的時候不在將創建邏輯暴露給客戶端,而是通過實現接口的方式創建對象,這種設計模式也是對象實例化的最佳方式。
概述
工廠模式的三種形態
- 簡單工廠(Simple Factory)
- 工廠方法(Factory Method)
- 抽象工廠(Abstract Factory)
簡單工廠
簡單工廠模式屬於工廠模式的小弟
,未被收納進GOF 23
中,但是也被頻繁使用
1.創建一個Animal
接口
interface Shape {
void draw();
}
2.創建Dog
和Pig
實現Animal
接口
class Circle implements Shape {
public Circle() {
System.out.println("創建圓形模型");
}
@Override
public void draw() {
System.out.println("畫了一個圓形");
}
}
class Square implements Shape {
public Square() {
System.out.println("創建了方形模型");
}
@Override
public void draw() {
System.out.println("畫了一個方形");
}
}
3.創建工廠類SimpleFactory
,定義一個基於參數信息實例化具體對象的方法
public class SimpleFactory {
private final static String CIRCLE = "CIRCLE";
private final static String SQUARE = "SQUARE";
public static Shape getFactory(String type) {
switch (type) {
case CIRCLE:
return new Circle();
case SQUARE:
return new Square();
default:
throw new NullPointerException("未描繪任何圖形");
}
}
public static void main(String[] args) {
Shape circle = SimpleFactory.getFactory(CIRCLE);
circle.draw();
Shape square = SimpleFactory.getFactory(SQUARE);
square.draw();
}
}
4.日誌
創建圓形模型
畫了一個圓形
創建了方形模型
畫了一個方形
分析: 從上述代碼中可以發現,簡單工廠
擁有一定判斷能力,構建結果取決於入參,使用起來也十分的方便,也正因爲使用太過方便
而導致高耦合
的情況,所有對象實例化都需要依賴它,一旦出問題,影響的會是整個系統
使用場景: 創建簡單,無複雜業務邏輯的對象
工廠方法
前面說到過簡單工廠模式
存在耦合,且違反了開閉原則
,那麼這一問題在工廠方法模式
中可以很容易的解決掉,它可以做到添加新的產品而不破壞已有代碼
工廠方法模式
:定義一個創建對象的接口,由它的實現類來決定具體實現,其模式又被稱爲工廠模式(Factory Pattern)
。
1.新增ImageReaderFactory
抽象工廠接口,用來構建具體的對象
interface ImageReader {
void read();
}
interface ImageReaderFactory {
ImageReader create();
}
2.相比單一實例化的簡單工廠模式
而言,方法工廠模式
更加的靈活,針對不同的產品(圖片讀取器)
提供不同的工廠。
class JpgReader implements ImageReader {
public JpgReader() {
System.out.println("創建Jpg讀取器");
}
@Override
public void read() {
System.out.println("讀取Jpg文件");
}
}
class PngReader implements ImageReader {
public PngReader() {
System.out.println("創建Png讀取器");
}
@Override
public void read() {
System.out.println("讀取Png文件");
}
}
class JpgFactory implements ImageReaderFactory {
@Override
public ImageReader create() {
System.out.println("實例化Jpg文件工廠");
return new JpgReader();
}
}
class PngFactory implements ImageReaderFactory {
@Override
public ImageReader create() {
System.out.println("實例化Png文件工廠");
return new PngReader();
}
}
3.創建測試類,當然實際使用過程中,實現工廠方法
除了可以實例化具體對象,還可以初始化某些資源配置,比如連接池、創建文件等
public class MethodFactory {
public static void main(String[] args) {
ImageReaderFactory png = new PngFactory();
ImageReader pngReader = png.create();
pngReader.read();
ImageReaderFactory jpg = new JpgFactory();
ImageReader jpgReader = jpg.create();
jpgReader.read();
}
}
4.日誌
實例化Png文件工廠
創建Png讀取器
讀取Png文件
實例化Jpg文件工廠
創建Jpg讀取器
讀取Jpg文件
優點:
- 屏蔽了客戶端實例化對象的細節,用戶只需要關心自己使用的工廠即可。
- 加入新的
產品(圖片讀取器)
,無需更改現有代碼,提高系統擴展性,符合開閉原則
- 具備
多態性
,又被稱爲多態工廠模式
缺點: 每次需要編寫新的對象和對象工廠類
,隨業務發展,一定程度上增加了系統複雜度
抽象工廠
抽象工廠模式
是爲創建一組對象提供提供的解決方案,與工廠方法模式相比
,抽象工廠模式中的具體工廠不只是創建某一種產品,而是負責一組(產品族)。抽象工廠模式(Abstract Factory Pattern)
:提供了創建一系列相互依賴對象的接口,無需指定具體類抽象工廠模式
是圍繞着一個超級工廠工作,創造其它的工廠類,也被稱爲工廠的工廠
,這種類型的設計模式是創造性的模式,因爲這種模式提供了創建對象的最佳方法之一。
起源
抽象工廠模式
的起源或者最早的應用,是用於創建分屬於不同操作系統的視窗構建。比如:命令按鍵(Button)與文字框(Text)都是視窗構建,在UNIX操作系統的視窗環境和Windows操作系統的視窗環境中,這兩個構建有不同的本地實現,它們的細節有所不同。
在每一個操作系統中,都有一個視窗構建組成的構建家族。在這裏就是Button和Text組成的產品族。而每一個視窗構件都構成自己的等級結構,由一個抽象角色給出抽象的功能描述,而由具體子類給出不同操作系統下的具體實現。
可以發現在上面的產品類圖中,有兩個產品的等級結構,分別是Button等級結構和Text等級結構。同時有兩個產品族,也就是UNIX產品族和Windows產品族。UNIX產品族由UNIX Button和UNIX Text產品構成;而Windows產品族由Windows Button和Windows Text產品構成。
系統對產品對象的創建需求由一個工程的等級結構滿足,其中有兩個具體工程角色,即UnixFactory和WindowsFactory。UnixFactory對象負責創建Unix產品族中的產品,而WindowsFactory對象負責創建Windows產品族中的產品。這就是抽象工廠模式的應用,抽象工廠模式的解決方案如下圖:
顯然,一個系統只能夠在某一個操作系統的視窗環境下運行,而不能同時在不同的操作系統上運行。所以,系統實際上只能消費屬於同一個產品族的產品。
在現代的應用中,抽象工廠模式的使用範圍已經大大擴大了,不再要求系統只能消費某一個產品族了。因此,可以不必理會前面所提到的原始用意。
摘抄自《JAVA與模式》之抽象工廠模式:http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
需求: 開發一款《王者榮耀》,支持多操作系統和多控制方式操作控制
和界面控制
,並提供相應的工廠類來封裝這些類的初始化過程
1.創建不同的操作系統接口
interface Linux {
void controller();
}
interface Windows {
void controller();
}
2.基於不同操作系統實現控制邏輯
class LinuxController implements Linux {
@Override
public void controller() {
System.out.println("Linux 控制 《王者榮耀》");
}
}
class WindowsController implements Windows {
@Override
public void controller() {
System.out.println("Windows 控制 《王者榮耀》");
}
}
3.創建一個工廠類,基於接口分別實現操作控制
和界面控制
兩種方式的工廠
interface AbstractFactory {
Linux installLinux();
Windows installWindows();
}
class OperationFactory implements AbstractFactory {
@Override
public Linux installLinux() {
System.out.println("安裝Linux操作控制系統");
return new LinuxController();
}
@Override
public Windows installWindows() {
System.out.println("安裝Windows操作控制系統");
return new WindowsController();
}
}
class InterfaceFactory implements AbstractFactory {
@Override
public Linux installLinux() {
System.out.println("安裝Linux界面控制系統");
return new LinuxController();
}
@Override
public Windows installWindows() {
System.out.println("安裝Windows界面控制系統");
return new WindowsController();
}
}
4.創建《王者榮耀》進行測試
public class KingGlory {
public static void main(String[] args) {
AbstractFactory operationFactory = new OperationFactory();
operationFactory.installLinux().controller();
operationFactory.installWindows().controller();
System.out.println("========================================================");
AbstractFactory interfaceFactory = new InterfaceFactory();
interfaceFactory.installLinux().controller();
interfaceFactory.installWindows().controller();
}
}
5.日誌
安裝Linux操作控制系統
Linux 控制 《王者榮耀》
安裝Windows操作控制系統
Windows 控制 《王者榮耀》
========================================================
安裝Linux界面控制系統
Linux 控制 《王者榮耀》
安裝Windows界面控制系統
Windows 控制 《王者榮耀》
分析
使用抽象工廠模式
來定義的一系列對象通常是相關或相互依賴的,這些產品對象就構成了一個產品族
,也就是抽象工廠定義了一個產品族
。這就帶來非常大的靈活性,切換產品族的時候,只要提供不同的抽象工廠實現就可以了,也就是說現在是以一個產品族作爲一個整體被切換,從上文中可以發現,如果我們需要切換控制方式
,只需要變更下對應的工廠類即可
優點:
- 分離接口和實現:客戶端使用抽象工廠來創建需要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦。
- 切換產品族變得容易:對於增加新的產品族,抽象工廠模式很好地支持了
開閉原則
,只需要增加具體產品並對應增加一個新的具體工廠,對已有代碼無須做任何修改(如:新增一種手柄操作支持)。
缺點:
- 不易擴展新產品:如果需要給整個產品族添加一個新的產品,那麼就需要修改抽象工廠,這樣就會導致修改所有的工廠實現類(如:新增一種操作系統的支持,那麼
Factory
代碼需要全部修改)。
使用場景:
- 一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有形態的工廠模式都是重要的。
- 這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
- 同屬於同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
- 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於實現。
- 說點什麼
全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter1/battcn-factory
- 個人QQ:1837307557
- battcn開源羣(適合新手):391619659
微信公衆號:battcn
(歡迎調戲)