1、什么是抽象工厂模式
抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
2、抽象工厂使用条件
使用抽象工厂模式一般要满足以下条件。
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
3、优缺点
- 优点:具体产品在应用层代码隔离,无须关心创建细节;将一个系列的产品族统一到一起创建。
- 缺点:规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口;增加了系统的抽象性和理解难度
4、抽象工厂模式实现
抽象工厂模式的主要角色如下。
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
抽象工厂模式结构图如图所示:
以华为、小米2个品牌,分别生产手机、路由器为例,代码如下(产品类别接口以及对应工厂接口):
/** * 手机产品接口 */ public interface IPhoneProduct { /** * 开机 */ void start(); /** * 关机 */ void shutdown(); /** * 拨打电话 */ void callUp(); /** * 发送短信 */ void sendSMS(); } /** * 路由器产品接口 */ public interface IRouterProduct { /** * 开机 */ void start(); /** * 关机 */ void shutdown(); /** * 开启wifi */ void openWifi(); /** * 设置参数 */ void setting(); } /** * 抽象产品工厂(定义了同一个产品族的产品生产行为) */ public interface IProductFactory { /** * 生产手机 * @return */ IPhoneProduct produceTelPhone(); /** * 生产路由器 * @return */ IRouterProduct produceRouter(); }
接下来看产品类:
/** * 华为手机产品 */ public class HuaweiPhone implements IPhoneProduct { @Override public void start() { System.out.println("开启华为手机"); } @Override public void shutdown() { System.out.println("关闭华为手机"); } @Override public void callUp() { System.out.println("用华为手机打电话"); } @Override public void sendSMS() { System.out.println("用华为手机发短信"); } } /** * 华为路由器产品 */ public class HuaweiRouter implements IRouterProduct { @Override public void start() { System.out.println("启动华为路由器"); } @Override public void shutdown() { System.out.println("关闭华为路由器"); } @Override public void openWifi() { System.out.println("打开华为路由器的wifi功能"); } @Override public void setting() { System.out.println("设置华为路由器参数"); } } /** * 小米手机产品 */ public class XiaomiPhone implements IPhoneProduct { @Override public void start() { System.out.println("开启小米手机"); } @Override public void shutdown() { System.out.println("关闭小米手机"); } @Override public void callUp() { System.out.println("用小米手机打电话"); } @Override public void sendSMS() { System.out.println("用小米手机发短信"); } } /** * 小米路由器产品 */ public class XiaomiRouter implements IRouterProduct { @Override public void start() { System.out.println("启动小米路由器"); } @Override public void shutdown() { System.out.println("关闭小米路由器"); } @Override public void openWifi() { System.out.println("打开小米路由器的wifi功能"); } @Override public void setting() { System.out.println("设置小米路由器参数"); } }
最后看产品工厂:
/** * 华为产品工厂 */ public class HuaweiProductFactory implements IProductFactory{ @Override public IPhoneProduct produceTelPhone() { System.out.println(">>>>>>生产华为手机"); return new HuaweiPhone(); } @Override public IRouterProduct produceRouter() { System.out.println(">>>>>>生产华为路由器"); return new HuaweiRouter(); } @Override public IComputer produceComput() { return null; } } /** * 小米产品工厂 */ public class XiaomiProductFactory implements IProductFactory { @Override public IPhoneProduct produceTelPhone() { System.out.println(">>>>>>生产小米手机"); return new XiaomiPhone(); } @Override public IRouterProduct produceRouter() { System.out.println(">>>>>>生产小米路由器"); return new XiaomiRouter(); } @Override public IComputer produceComput() { return null; } }
测试类如下:
/** * 使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。 */ public class Test { public static void main(String[] args) { System.out.println("===================小米系列产品================="); //小米产品工厂实例 IProductFactory xiaomiProductFactory = new XiaomiProductFactory(); //生产小米路由器 IRouterProduct xiaomiRouter = xiaomiProductFactory.produceRouter(); xiaomiRouter.start(); xiaomiRouter.setting(); xiaomiRouter.openWifi(); xiaomiRouter.shutdown(); //生产小米手机 IPhoneProduct xiaomiPhone = xiaomiProductFactory.produceTelPhone(); xiaomiPhone.start(); xiaomiPhone.callUp(); xiaomiPhone.sendSMS(); xiaomiPhone.shutdown(); System.out.println("===================华为系列产品================="); //华为产品工厂实例 IProductFactory huaweiProductFactory = new HuaweiProductFactory(); //生产华为路由器 IRouterProduct huaweiRouter = huaweiProductFactory.produceRouter(); huaweiRouter.start(); huaweiRouter.setting(); huaweiRouter.openWifi(); huaweiRouter.shutdown(); //生产华为手机 IPhoneProduct huaweiPhone = huaweiProductFactory.produceTelPhone(); huaweiPhone.start(); huaweiPhone.callUp(); huaweiPhone.sendSMS(); huaweiPhone.shutdown(); } }
测试结果如下:
===================小米系列产品================= >>>>>>生产小米路由器 启动小米路由器 设置小米路由器参数 打开小米路由器的wifi功能 关闭小米路由器 >>>>>>生产小米手机 开启小米手机 用小米手机打电话 用小米手机发短信 关闭小米手机 ===================华为系列产品================= >>>>>>生产华为路由器 启动华为路由器 设置华为路由器参数 打开华为路由器的wifi功能 关闭华为路由器 >>>>>>生产华为手机 开启华为手机 用华为手机打电话 用华为手机发短信 关闭华为手机
5、抽象工厂模式的应用场景
抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。
抽象工厂模式通常适用于以下场景:
- 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
- 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
- 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
6、抽象工厂模式的扩展
抽象工厂模式的扩展有一定的“开闭原则”倾斜性:
- 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
- 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。