在上篇文章工厂模式——工厂方法模式中,我们根据案例学习了工厂方法模式知识点。此篇我们引入新的需求场景下,在对比工厂方法模式下学习抽象工厂模式的运用。
产品族和等级结构
为了更清晰地理解抽象工厂模式,需要先引入两个概念:
- 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视、海尔洗衣机。
- 等级结构:产品等级结构即产品的继承结构,如抽象电视机与具体品牌的电视机之间构成了一个产品等级结构。
由此可见,工厂方法模式就是一个产品族下的等级结构体系,是抽象工厂模式的特殊情况。
抽象工厂模式组成角色
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口或抽象父类。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
此模式下的抽象工厂创建的是一族产品中的所有子产品,而工厂方法模式下的抽象工厂对应的是子产品的声明。即工厂方法模式下的抽象工厂角色定位被抽象工厂模式下的抽象工厂角色的方法代替。
抽象工厂模式案例解析
案例情景:王师傅和李师傅各轮值一天,但想吃王师傅做的早饭、午饭、晚饭。
若要今天吃到王师傅做的早饭,就不能在今天吃李师傅做的午饭或晚饭,因为当天只会有一个师傅值班。
王师傅和李师傅做的饭就是两个产品族。做饭和做早饭遵循等级结构中的继承结构。
以往的工厂方法模式却无法区分早饭、午饭、晚饭分属的产品族,这就需抽象工厂模式的由来。
抽象工厂接口,如下:
/**
* 抽象工厂- 李师傅做饭
*
* @author jinzifu
* @create 2018/2/23 22:04
*/
public interface ILiFoodFactory {
/**
* 早饭
*
* @return
*/
IMakeFood getBreakfest();
/**
* 午饭
*
* @return
*/
IMakeFood getLunch();
/**
* 晚饭
*
* @return
*/
IMakeFood getDinner();
}
该接口内的方法声明了一个产品族内的所有子产品,如李师傅做的早饭、午饭、晚饭。早饭、午饭、晚饭是两个产品族(王师傅和李师傅)共有的等级结构。
具体工厂类,如下:
/**
* 具体工厂-李师傅做饭
*
* @author jinzifu
* @create 2018/2/24 11:11
*/
public class LiFoodFactory implements ILiFoodFactory {
public LiFoodFactory() {
System.out.println("李师傅值班中...");
}
@Override
public IMakeFood getBreakfest() {
return new Breakfest();
}
@Override
public IMakeFood getLunch() {
return new Lunch();
}
@Override
public IMakeFood getDinner() {
return new Dinner();
}
}
具体工厂实现抽象工厂接口中的所有具体产品,如早饭、午饭、晚饭。
此模式下的抽象产品和具体产品与工厂方法模式下承担的角色和分工一样,不做赘述。
外部测试及打印如下:
LiFoodFactory liFoodFactory = new LiFoodFactory();
liFoodFactory.getBreakfest().makeFood();
liFoodFactory.getLunch().makeFood();
liFoodFactory.getDinner().makeFood();
李师傅值班中...
早饭
午饭
晚饭
抽象工厂模式下,产品的扩展需更改抽象工厂的接口方法,违背了“开闭原则”。
工厂模式的使用场景
- 产品的创建过程较为复杂,且创建和使用分离开进行更好时宜采用工厂模式。
- 系统产品分属多个产品族,产品族之间有相似的产品等级结构,且同一时刻系统只消费其中某一族的产品时,宜采用抽象工厂模式。
- 单一产品族时,多采用工厂方法模式。只需增加工厂类和具体产品类,符合“开闭原则”。