设计模式-抽象工厂模式
抽象工厂模式Abstract Factory提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。使用普通工厂方法每次只能负责生产某单一类型的对象一旦遇到需要“成套搭配”的产品场景极其容易产生配置混乱 最优方案是由抽象工厂定义一整套相关产品的创建规范再由具体的工厂来负责这一整套产品族的具体实现客户端只需要和接口打交道就能打包获取一整套相互兼容的产品。AbstractFactory接口声明了一组用于创建一族产品的方法例如 CreateProductA、CreateProductB每个方法负责创建一种类型的产品。优缺点优点产品族一致性当一个产品族中的多个对象被设计成一起工作时它能保证客户端始终只使用同一个产品族中的对象杜绝“品牌混用”导致的兼容性问题极佳的解耦性客户端不仅不用关心对象的具体创建逻辑甚至不知道最终使用的是哪个具体的产品类实现了调用端与产品实现的完全隔离批量切换极其简单修改具体工厂的实例化语句就能在代码中一键切换整个系统的产品风格、运行环境或数据库类型。缺点难以扩展新产品种类如果产品族里需要增加一个全新的产品角色比如原来只有键盘、鼠标现在要新增一个耳机必须修改抽象工厂的底层接口所有实现该接口的具体工厂类全部都要跟着改动严重违背了“开闭原则”类爆炸问题由于系统需要为每一个产品族、每一个产品等级准备对应的接口和具体类前期架构中类的数量会极速成倍膨胀带来较高的阅读与维护成本。举个例子RS工作室给新来的两名程序员小伙伴配置桌面办公装备键盘 鼠标。咱们采购外设一般讲究“生态套装”要么全选极简办公风要么全选机械朋克风。如果混用不仅外观极其别扭各家的驱动程序还得同时装好几个如果不使用抽象工厂模式大家都是在 main 方法里随便 newpublic class Office { public static void main(String[] args) { // 小A想组一台机器 Keyboard k1 new PunkKeyboard(); Mouse m1 new MinimalistMouse(); k1.type(); m1.click(); } }敲击机械朋克键盘咔哒咔哒 点击极简静音鼠标无声轻触...输出结果虽然能用但观察到 小A不小心买成了“朋克风键盘 极简风鼠标”不仅桌面上看起来辣眼睛而且两者驱动不兼容。主要缺点控制不了产品组合的搭配一旦全公司几百人同时配置手一抖就会产生各种奇奇怪怪的“杂牌军”组合。但是使用抽象工厂呢我们将键盘和鼠标死死绑定为一个“产品族”// 1. 定义产品接口 public interface Keyboard { void type(); } public interface Mouse { void click(); } // 2. 朋克风产品族 public class PunkKeyboard implements Keyboard { public void type() { System.out.println(敲击机械朋克键盘咔哒咔哒有劲); } } public class PunkMouse implements Mouse { public void click() { System.out.println(点击朋克鼠标RGB发光炫酷触发); } } // 3. 极简风产品族 public class MinimalistKeyboard implements Keyboard { public void type() { System.out.println(敲击极简键盘巧克力键帽轻柔舒适); } } public class MinimalistMouse implements Mouse { public void click() { System.out.println(点击极简鼠标人体工学静音无声); } } // 4. 抽象工厂规定每个具体工厂必须出产一个键盘和一个鼠标 public interface PeripheralFactory { Keyboard createKeyboard(); Mouse createMouse(); } // 5. 具体工厂A负责专门生产朋克套装 public class PunkFactory implements PeripheralFactory { public Keyboard createKeyboard() { return new PunkKeyboard(); } public Mouse createMouse() { return new PunkMouse(); } } // 6. 具体工厂B负责专门生产极简套装 public class MinimalistFactory implements PeripheralFactory { public Keyboard createKeyboard() { return new MinimalistKeyboard(); } public Mouse createMouse() { return new MinimalistMouse(); } }客户端调用时只需要指定一个具体工厂产出的设备天然配对public class Studio { public static void main(String[] args) { // 行政人员决定今天给新员工配“机械朋克套装” PeripheralFactory factory new PunkFactory(); // 程序员只管从工厂领设备绝对不会领错品牌 Keyboard myKeyboard factory.createKeyboard(); Mouse myMouse factory.createMouse(); myKeyboard.type(); myMouse.click(); } }敲击机械朋克键盘咔哒咔哒有劲 点击朋克鼠标RGB发光炫酷触发全程通过PunkFactory统一打包出产如果有一天老板决定全工作室换成极简风只需将new PunkFactory()改为new MinimalistFactory()后续所有生成外设的代码一字不改完美实现成套组装与一键切换。抽象工厂模式的核心术语与演进产品等级结构Product Class即产品的类型。比如“键盘”是一个产品等级“鼠标”是另一个产品等级。在代码里就是它们各自的顶级接口。产品族Product Family由同一个具体工厂生产位于不同产品等级结构中的一组产品。比如“朋克风键盘 朋克风鼠标”共同构成了“朋克产品族”。退化为工厂方法当抽象工厂类里只含有一个创建产品的方法时即只有一个产品等级比如只生产键盘抽象工厂模式就自动退化成了普通的工厂方法模式。搭配单例模式使用在实际开发中具体工厂类比如上面的PunkFactory在全系统中通常只需要存在一个实例就足够了因此具体工厂经常结合单例模式Singleton共同实现。适用场景多套 UI 皮肤/主题切换例如跨平台桌面软件需要同时支持 Windows 和 macOS 风格的控件按钮、文本框、滚动条游戏系统内的套装功能火系护甲火系武器 vs 冰系护甲冰系武器多数据库兼容架构系统需要同时兼容 MySQL 和 Oracle由于数据库连接Connection、命令操作Command、结果集ResultSet必须彼此配套极其适合用抽象工厂统一生产硬件设备生态套件比如不同品牌的智能家居控制系统苹果 HomeKit 协议芯片组件 vs 小米米家协议组件多环境基础组装在软件工程中针对开发环境Dev、测试环境Test和生产环境Prod分别成套提供不同的日志记录器、缓存解析器与网络请求客户端。