什麼是抽象工廠
提供了一個用來創建一組相關或相互依賴對象的接口,而不需要指定具體的類。與工廠方法模式相比,抽象工廠模式不僅創建單一對象,還創建一組產品族(即多個相關的產品)。
主要特點:
- 產品族:抽象工廠模式是用來創建一組相關產品的工廠。每個具體工廠負責創建一組具體的產品。
- 解耦:抽象工廠模式能夠讓客戶端在不依賴具體類的情況下創建一組對象。
適用場景:當系統中有多個產品族,而客戶端需要根據具體情況創建不同的產品族時。
工廠 vs 抽象工廠
| 特徵 | 工廠模式 (Factory Method) | 抽象工廠模式 (Abstract Factory) | 
| 目標 | 創建單一產品 | 創建一組相關的產品 | 
| 重點 | 關注如何創建一個產品 | 關注如何創建一組互相關聯的產品 | 
| 產品數量 | 只創建一個產品類型 | 同時創建多個相關的產品類型 | 
| 擴展性 | 易於擴展單一產品的類型 | 易於擴展產品族,添加新的產品族 | 
| 複雜性 | 相對簡單,適用於需要創建單一產品的情況 | 較複雜,適用於需要創建多個相關產品並且這些產品屬於同一族群的情況 | 
| 客戶端 | 客戶端使用具體工廠來創建單一產品 | 客戶端使用抽象工廠來創建一組相關的產品 | 
| 適用場景 | 當創建一個對象的過程需要封裝,且該對象是可擴展的 | 當系統中有多個產品族,且客戶端需要根據情況選擇創建一個產品族時 | 
| 示例 | 創建不同類型的單一產品(如不同的交通工具:車、船、飛機) | 創建一組相關產品(如不同系列的家具:桌子、椅子、沙發) | 
範例
家具有不同的功能,也有不同的風格

重構前
多層次equal 判斷
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 
 | public class FurnitureService {
 public void createFurniture(String furnitureType, String style) {
 if ("chair".equalsIgnoreCase(furnitureType)) {
 if ("modern".equalsIgnoreCase(style)) {
 System.out.println("創建現代風格椅子,功能:坐");
 } else if ("classic".equalsIgnoreCase(style)) {
 System.out.println("創建古典風格椅子,功能:坐");
 } else if ("industrial".equalsIgnoreCase(style)) {
 System.out.println("創建工業風格椅子,功能:坐");
 } else {
 throw new RuntimeException("未知的椅子風格:" + style);
 }
 } else if ("sofa".equalsIgnoreCase(furnitureType)) {
 if ("modern".equalsIgnoreCase(style)) {
 System.out.println("創建現代風格沙發,功能:坐");
 } else if ("classic".equalsIgnoreCase(style)) {
 System.out.println("創建古典風格沙發,功能:躺");
 } else if ("industrial".equalsIgnoreCase(style)) {
 System.out.println("創建工業風格沙發,功能:坐");
 } else {
 throw new RuntimeException("未知的沙發風格:" + style);
 }
 } else if ("coffeetable".equalsIgnoreCase(furnitureType)) {
 if ("modern".equalsIgnoreCase(style)) {
 System.out.println("創建現代風格咖啡桌,功能:放置咖啡");
 } else if ("classic".equalsIgnoreCase(style)) {
 System.out.println("創建古典風格咖啡桌,功能:放置咖啡");
 } else if ("industrial".equalsIgnoreCase(style)) {
 System.out.println("創建工業風格咖啡桌,功能:放置咖啡");
 } else {
 throw new RuntimeException("未知的咖啡桌風格:" + style);
 }
 } else {
 throw new RuntimeException("未知的家具類型:" + furnitureType);
 }
 }
 }
 
 
 | 
重構開始

圖為 https://refactoring.guru/ 的示意圖,以下code有做變更
定義包含返回訊息的enum
將功能放入enum,並定義家具的enum
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 
 | public enum FurnitureType {CHAIR("椅子", Collections.singletonList(FunctionalityType.SIT)),
 SOFA("沙發", Arrays.asList(FunctionalityType.SIT, FunctionalityType.LIE_DOWN)),
 COFFEE_TABLE("咖啡桌", Collections.singletonList(FunctionalityType.PLACE_COFFEE));
 
 private final String name;
 private final List<FunctionalityType> functionalities;
 
 FurnitureType(String name, List<FunctionalityType> functionalities) {
 this.name = name;
 this.functionalities = functionalities;
 }
 
 public String getName() {
 return name;
 }
 
 public List<FunctionalityType> getFunctionalities() {
 return functionalities;
 }
 }
 
 
 public enum StyleType {
 MODERN("現代"),
 CLASSIC("古典"),
 INDUSTRIAL("工業");
 
 private final String name;
 
 StyleType(String name) {
 this.name = name;
 }
 
 public String getName() {
 return name;
 }
 }
 
 
 public enum FunctionalityType {
 SIT("坐"),
 LIE_DOWN("躺"),
 PLACE_COFFEE("放置咖啡");
 
 private final String action;
 
 FunctionalityType(String action) {
 this.action = action;
 }
 
 public String getAction() {
 return action;
 }
 }
 
 | 
定義家具、風格和功能的接口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | public interface Furniture {void describe();
 }
 
 
 public interface Style {
 String getStyleName();
 }
 
 
 public interface Functionality {
 String getFunctionality();
 }
 
 | 
實現適配器,將家具、風格和功能組合:
由於功能與家具以做配對,使用適配器模式將風格和家具組合
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | public class FurnitureAdapter implements Furniture {private Style style;
 private FurnitureType furnitureType;
 
 public FurnitureAdapter(FurnitureType furnitureType, Style style) {
 this.furnitureType = furnitureType;
 this.style = style;
 }
 
 @Override
 public void describe() {
 System.out.print("創建" + style.getStyleName() + "風格的" + furnitureType.getName() + ",功能:");
 List<FunctionalityType> functionalities = furnitureType.getFunctionalities();
 System.out.println(functionalities.stream()
 .map(FunctionalityType::getAction)
 .collect(Collectors.joining("、")));
 }
 }
 
 | 
實現風格
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | public class ModernStyle implements Style {@Override
 public String getStyleName() {
 return StyleType.MODERN.getName();
 }
 }
 
 
 public class ClassicStyle implements Style {
 @Override
 public String getStyleName() {
 return StyleType.CLASSIC.getName();
 }
 }
 
 
 public class IndustrialStyle implements Style {
 @Override
 public String getStyleName() {
 return StyleType.INDUSTRIAL.getName();
 }
 }
 
 | 
實現功能
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | public class SitFunctionality implements Functionality {@Override
 public String getFunctionality() {
 return FunctionalityType.SIT.getAction();
 }
 }
 
 
 public class LieDownFunctionality implements Functionality {
 @Override
 public String getFunctionality() {
 return FunctionalityType.LIE_DOWN.getAction();
 }
 }
 
 
 public class PlaceCoffeeFunctionality implements Functionality {
 @Override
 public String getFunctionality() {
 return FunctionalityType.PLACE_COFFEE.getAction();
 }
 }
 
 | 
定義抽象工廠
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public abstract class AbstractFurnitureFactory {
 protected abstract Style createStyle();
 
 
 public Furniture createFurniture(FurnitureType furnitureType) {
 Style style = createStyle();
 return new FurnitureAdapter(furnitureType, style);
 }
 }
 
 
 | 
實現具體的工廠
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 
 public class ModernFurnitureFactory extends AbstractFurnitureFactory {
 @Override
 protected Style createStyle() {
 return new ModernStyle();
 }
 }
 
 
 public class ClassicFurnitureFactory extends AbstractFurnitureFactory {
 @Override
 protected Style createStyle() {
 return new ClassicStyle();
 }
 }
 
 
 public class IndustrialFurnitureFactory extends AbstractFurnitureFactory {
 @Override
 protected Style createStyle() {
 return new IndustrialStyle();
 }
 }
 
 
 | 
test:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | public class ApiTest {
 @Test
 public void testFurnitureAdapter() {
 Style style = new ModernStyle();
 FurnitureType furnitureType = FurnitureType.CHAIR;
 Furniture furniture = new FurnitureAdapter(furnitureType, style);
 furniture.describe();
 
 style = new ClassicStyle();
 furnitureType = FurnitureType.SOFA;
 furniture = new FurnitureAdapter(furnitureType, style);
 furniture.describe();
 
 style = new IndustrialStyle();
 furnitureType = FurnitureType.COFFEE_TABLE;
 furniture = new FurnitureAdapter(furnitureType, style);
 furniture.describe();
 }
 }
 
 | 
| 12
 3
 
 | 創建現代風格的椅子,功能:坐創建古典風格的沙發,功能:躺
 創建工業風格的咖啡桌,功能:放置咖啡
 
 | 
圖源/參考資料:
https://refactoring.guru/
重學java設計模式-小博哥