定义
提供一个接口,该接口创建相关或相互依赖的对象家族,客户端只需调用接口实现类即可获取同族的不同等级的产品。
在定义中,产品等级和产品簇是从不同维度对产品进行划分,产品等级从产品的功能出发,产品簇从产品的生产者出发。以华为和小米为例,小米公司生产的所有产品属于同一产品族(族表示有血缘关系),即小米手机和小米手环是同属小米产品族,同样地,华为公司生产的所有产品同属华为产品族。小米公司生产的小米手机和华为公司生产的华为手机同属同一产品等级,小米手机和华为手机虽然没有关系,但他俩都属于手机等级。类似地,还有手环等级、耳机等级等。
产品族(小米) | 产品族(华为) | |
---|---|---|
产品等级(手机) | 小米手机 | 华为手机 |
产品等级(手环) | 小米手环 | 华为手环 |
此列是抽象工厂要向客户端输出的同属一个产品族的多个产品,即手机和手环 | 此列是抽象工厂要向客户端输出的同属一个产品族的多个产品,即手机和手环 |
抽象工厂的中心词是工厂,工厂中定义了生产不同等级产品的方法,且工厂创建的所有产品属于同族,强调生产多个产品。抽象的含义指工厂中生产产品的方法是抽象的,需要实例化才能被客户端使用,强调工厂中所有生产方法是抽象的。
模式结构
抽象工厂模式包含角色同工厂方法类似。从定义可知,除去客户端外,该模式包含了四种角色。从两个平行的类层级出发,可对这四种角色分类。
- 相关簇
- 工厂接口和工厂接口实现类属于工厂簇相关,两者之间存在“高低层”的关系
- 抽象产品和产品实例都属于产品簇相关,两者之间存在“高低层”的关系
- 等级
- 工厂接口和抽象产品属于一个等级,两者可以通信
- 工厂接口实现类和产品实例属于一个等级,两者可以通信
他们之间的类图和时序图如下
代码实践
本文以抽象工厂生产手机和手环,小米工厂和华为工厂为具体实现类为例。首先是对抽象层的结构设计。
抽象工厂接口,包括生产手机方法和生产手环方法。
public interface BaseFactory {
BaseMobile createMobile();
BaseWristband createWristband();
}
在以上代码段中,BaseMobile和BaseWristband分别代表抽象手机和抽象手环,部分核心代码如下
/**
* 抽象手机接口
*/
public interface BaseMobile {
//对象业务方法
void printName();
}
/**
* 抽象手环接口
*/
public interface BaseWristband {
//对象业务方法
void printName();
}
在定义接口规范之后,以小米和华为为例,依次实现抽象手机、抽象手环、抽象工厂。小米产品族代码如下
/**
* @author gj
* @description 小米手机实现类
* @date 2021/1/5
**/
public class BaseMobileMiImpl implements BaseMobile {
@Override
public void printName() {
System.out.println("这是一个小米手机对象");
}
}
/**
* @author gj
* @description 小米手环实现类
* @date 2021/1/5
**/
public class BaseWirstbandMiImpl implements BaseWristband {
@Override
public void printName() {
System.out.println("这是一个小米手环对象");
}
}
/**
* @author gj
* @description 小米抽象工厂实现类
* @date 2021/1/5
**/
public class BaseFactoryMiImpl implements BaseFactory {
@Override
public BaseMobile createMobile() {
//最终对象的创建类在此处
return new BaseMobileMiImpl();
}
@Override
public BaseWristband createWristband() {
//最终对象的创建类在此处
return new BaseWirstbandMiImpl();
}
}
华为产品族代码如下
/**
* @author gj
* @description 华为手机实现类
* @date 2021/1/5
**/
public class BaseMobileHuaImpl implements BaseMobile {
@Override
public void printName() {
System.out.println("这是一个华为手机对象");
}
}
/**
* @author gj
* @description 华为手机实现类
* @date 2021/1/5
**/
public class BaseWristbandHuaImpl implements BaseWristband {
@Override
public void printName() {
System.out.println("这是一个华为手环对象");
}
}
/**
* @author gj
* @description 华为抽象工厂实现类
* @date 2021/1/5
**/
public class BaseFactoryHuaImpl implements BaseFactory {
@Override
public BaseMobile createMobile() {
return new BaseMobileHuaImpl();
}
@Override
public BaseWristband createWristband() {
return new BaseWristbandHuaImpl();
}
}
完成实例化之后,即可在客户端调用。客户端代码如下
/**
* @author gj
* @description 客户端
* @date 2021/1/5
**/
public class ClinetTest {
public static void main(String[] args) {
//创建小米工厂
BaseFactory baseFactory = new BaseFactoryMiImpl();
//工厂生产手机对象,这个对象实质上是小米手机对象
BaseMobile mobile = baseFactory.createMobile();
//工厂生产手环对象,这个对象实质上是小米手环对象
BaseWristband wristband = baseFactory.createWristband();
//使用小米手机对象的方法
mobile.printName();
//使用小米手环对象的方法
wristband.printName();
//创建华为工厂
BaseFactoryHuaImpl baseFactoryHua = new BaseFactoryHuaImpl();
//工厂生产手机对象,这个对象实质上是华为手机对象
BaseMobile mobile1 = baseFactoryHua.createMobile();
//工厂生产手环对象,这个对象实质上是华为手环对象
BaseWristband wristband1 = baseFactoryHua.createWristband();
//使用华为手机对象的方法
mobile1.printName();
//使用华为手环对象的方法
wristband1.printName();
}
}
以上代码在idea中生成的类图如下
源码分析
在java.sql.connection中使用了抽象工厂模式,具体参考资料抽象工厂之connection解析。
特点
-
优点
- 模式的结构基于对象组合,而不是继承。工厂方法是基于继承。
- 通过工厂名即可获取对应产品,不必关系产品的创建过程。同工厂方法类似
- 一个工厂可创建产品族,解决了工厂方法只能创建一个产品的缺点。
- 符合开闭原则。当创建新产品族时,不需要修改抽象层的规范,直接实现抽象层接口即可。
-
缺点
-
当新产品族中增加新产品时,需要修改抽象层代码和所有实现类,违反开闭原则,
创建新产品族符合开闭原则,而新增产品时违反开闭原则,注意区分理解。
-
适用场景
同简单工厂模式和工厂方法类似,抽象工厂的基本作用是生产对象。特别地,抽象工厂能够生产多个同族产品,因此其适用场景同产品族相关。
- 封装创建过程。系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
- 创建产品族。当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
- 适用产品族。系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
参考资料
- HeadFirst设计模式
- 抽象工厂模式(详解版)
- 抽象工厂之connection解析
- 抽象工厂模式