小張的工廠進化史——工廠模式
- 一、簡單工廠模式:全能生產線
- 二、工廠方法模式:分品牌代工
- 三、抽象工廠模式:生態產品族
- 四、三種模式核心對比表
- 五、結合Spring實現簡單工廠(實踐)
小張從華強北起家,最初只有一條組裝線,根據訂單參數(手機/平板)手動切換生產流程。隨著訂單量激增,他經歷了三次產業升級:
- 階段1:全能生產線通過指令切換產品(簡單工廠模式)
- 階段2:引入代工廠分品牌生產(工廠方法模式)
- 階段3:打造生態產品族統一管理(抽象工廠模式)
一、簡單工廠模式:全能生產線
場景:小張初期用一條生產線,通過參數指令生產不同電子產品。
代碼示例:
// 抽象產品:電子設備接口
public interface Device {void boot();
}// 具體產品:手機
public class Phone implements Device {@Overridepublic void boot() { System.out.println("【簡單工廠】手機開機:Android系統啟動");}
}// 具體產品:平板
public class Tablet implements Device {@Overridepublic void boot() { System.out.println("【簡單工廠】平板開機:Android系統啟動");}
}// 簡單工廠類
public class ElectronicsFactory {public static Device createDevice(String type) {if ("phone".equalsIgnoreCase(type)) {return new Phone();} else if ("tablet".equalsIgnoreCase(type)) {return new Tablet();}throw new IllegalArgumentException("不支持的設備類型");}
}// 客戶端調用
public class Client {public static void main(String[] args) {Device phone = ElectronicsFactory.createDevice("phone");phone.boot(); // 輸出:手機開機...}
}
特點:
- 參數化創建:通過
if-else
判斷生產設備,違反開閉原則(新增產品需修改工廠類) - 適用場景:初期產品線單一(如僅手機和平板)
二、工廠方法模式:分品牌代工
場景:小張引入華為、小米代工廠,各品牌獨立生產設備。
代碼示例:
// 抽象工廠接口
public interface DeviceFactory {Device createDevice();
}// 具體工廠:華為代工廠
public class HuaweiFactory implements DeviceFactory {@Overridepublic Device createDevice() {return new HuaweiPhone(); // 華為手機}
}// 具體產品:華為手機
public class HuaweiPhone implements Device {@Overridepublic void boot() {System.out.println("【工廠方法】華為手機:HarmonyOS啟動");}
}// 客戶端調用
public class Client {public static void main(String[] args) {DeviceFactory factory = new HuaweiFactory();Device phone = factory.createDevice();phone.boot(); // 輸出:華為手機...}
}
特點:
- 多態擴展:新增品牌(如OPPO)只需添加新工廠類,符合開閉原則
- 類爆炸:每新增一個品牌需增加2個類(工廠+產品)
三、抽象工廠模式:生態產品族
場景:小張擴展生態鏈,生產同一品牌的多類產品(手機+耳機),確保設計兼容。
代碼示例:
// 抽象工廠接口
public interface BrandFactory {Phone createPhone();Earphones createEarphones();
}// 具體工廠:蘋果生態
public class AppleFactory implements BrandFactory {@Overridepublic Phone createPhone() {return new iPhone(); // 蘋果手機}@Overridepublic Earphones createEarphones() {return new AirPods(); // 蘋果耳機}
}// 關聯產品族
public class iPhone implements Phone {@Overridepublic void boot() {System.out.println("【抽象工廠】iPhone開機:iOS啟動");}
}
public class AirPods implements Earphones {public void connect() {System.out.println("【抽象工廠】AirPods自動配對");}
}// 客戶端調用
public class Client {public static void main(String[] args) {BrandFactory factory = new AppleFactory();factory.createPhone().boot(); // 輸出:iPhone開機...factory.createEarphones().connect(); // 輸出:AirPods自動配對...}
}
特點:
- 產品族兼容:確保同一品牌風格統一(如蘋果極簡設計)
- 接口膨脹:新增品牌需實現全套接口(如華為生態需實現createPhone()和createEarphones())
四、三種模式核心對比表
簡單工廠模式 | 工廠方法模式 | 抽象工廠模式 | |
---|---|---|---|
核心目標 | 快速生產單一產品 | 分品牌靈活擴展 | 創建兼容的生態產品族 |
擴展性 | ? 差(需修改代碼) | ? 優(新增工廠類) | ? 差(需實現全套接口) |
類復雜度 | 1工廠類 + N產品類 | N工廠類 + N產品類 | M工廠類 + M×N產品類 |
設計原則 | 違反開閉原則 | 符合開閉原則 | 符合接口隔離原則 |
適用場景 | 初期單一產線(手機/平板) | 多品牌代工(華為/小米) | 生態鏈產品(蘋果手機+耳機) |
五、結合Spring實現簡單工廠(實踐)
詳細內容可參考:【當模板方法模式遇上工廠模式:一道優雅的烹飪架構設計】
抽象類(或者 接口)
public abstract class AbstractCooking {protected CookEnum cookEnum;protected abstract void aromaBlasting();}
枚舉類
/*** 菜品枚舉類*/
public enum CookEnum {KUNG_PAO_CHICKEN("kungPaoChicken", "宮保雞丁"),MAPO_TO_FU("mapoTofu", "麻婆豆腐");private final String code;private final String name;CookEnum(String code, String name) {this.code = code;this.name = name;}....
}
宮保雞丁
/*** 宮保雞丁*/
@Service
public class KungPaoChicken extends AbstractCooking {public KungPaoChicken() {this.cookEnum = CookEnum.KUNG_PAO_CHICKEN;}@Overrideprotected void aromaBlasting() {System.out.println("蔥姜蒜爆香");}
}
麻婆豆腐
/*** 麻婆豆腐*/
@Service
public class MapoTofu extends AbstractCooking {public MapoTofu() {this.cookEnum = CookEnum.MAPO_TO_FU;}@Overrideprotected void aromaBlasting() {System.out.println("煸炒郫縣豆瓣醬+花椒粒");}
}
工廠類
@Service
public class CookFactory implements InitializingBean {// Spring啟動時,會依賴注入 所有的AbstractCooking的bean,注入到cookings@Autowiredprivate List<AbstractCooking> cookings;// 定義Map存儲 bean的映射關系private Map<CookEnum, AbstractCooking> cookingMap = new HashMap<>();public AbstractCooking getCookingByCode(String code) {CookEnum cookEnum = CookEnum.getByCode(code);return cookingMap.get(cookEnum);}// CookFactory的bean對象在初始化階段,動態把 AbstractCooking的所有bean 設置到cookingMap (動態擴展的關鍵)@Overridepublic void afterPropertiesSet() throws Exception {for (AbstractCooking cooking: cookings) {cookingMap.put(cooking.getCookEnum(), cooking);}}
}