从设计模式分类图中可以看到抽象工厂模式是经典的创建型设计模式之一。也可以看到抽象工厂模式是对象型创建模式。
阅读过我分享的《设计模式:(1)工厂方法模式》的朋友一定对工厂方法模式的特点和作用有些了解了。工厂方法模式封装了一类产品创建组装的细节,使调用者不会参与到产品的组装细节当中,这样就会使调用者轻松的实现对所需产品(对象)的获取,也降低了对象间的耦合,使系统的可扩展性增强。
工厂方法模式只是针对一类产品的创建,而今天所要分享的抽象工厂模式是针对一系列产品的创建。
首先在面向对象的开发中我们经常会发现在某一个对象中同时依赖两个以上的不同种类的对象,这两个不同的依赖对象就是一系列产品。也就是说对于一个对象A他的出现必然会依赖一组对象B1,B2,B3....等等,参照依赖一个对象的获取使用工厂方法模式,那么一系列的依赖对象就采用抽象工厂模式。
意图:为创建一组相关或相互依赖的对象提供一个接口,无需指定它们的具体类。
特点:
-
抽象工厂模式是工厂方法模式的进一步衍生,针对的是一族(系列)产品。每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。
-
可用来生产不同产品族的全部产品。
-
实现了创建者和调用者的分离。
适用情况:
-
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。 -
需要强调一系列相关的产品对象的设计以便进行联合使用时。
-
提供一个产品类库,而只想显示它们的接口而不是实现时。
结构UML图:
从类图中可以看到,抽象工厂是由四种角色组成,与工厂方法模式的角色类相似,其中:
-
AbstractFactory 抽象工厂接口,声明一个创建抽象产品对象的操作接口。
-
ConcreteFactory 具体工厂类,实现创建具体产品的操作。
-
AbstractProduct 抽象产品接口,为一类产品对象创建一个接口。
-
Product 具体产品,定义一个将被相应的具体工厂创建的产品对象,实现AbstractProduct接口。
-
Client 客户端,仅使用由AbstractFactory和AbstractProduct声明的接口。
模式标准代码:
//产品A
interface ProductA {
publicvoid method1();
publicvoid method2();
// 更多产品逻辑.....
}
// 产品B
interface ProductB {
publicvoid method1();
publicvoid method2();
// 更多产品逻辑.....
}
// 产品A具体实现:等级为1的产品A
class ProductA1 implements ProductA {
@Override
publicvoid method1() {
System.out.println("等级为1的产品A的逻辑");
}
@Override
publicvoid method2() {
// 业务逻辑处理代码
}
// 更多产品逻辑.....
}
// 产品A具体实现:等级为2的产品A
class ProductA2 implements ProductA {
@Override
publicvoid method1() {
System.out.println("等级为2的产品A的逻辑");
}
@Override
publicvoid method2() {
// 业务逻辑处理代码
}
// 更多产品逻辑.....
}
// 产品B具体实现:等级为1的产品B
class ProductB1 implements ProductB {
@Override
publicvoid method1() {
System.out.println("等级为1的产品B的逻辑");
}
@Override
publicvoid method2() {
// 业务逻辑处理代码
}
// 更多产品逻辑.....
}
// 产品B具体实现:等级为2的产品B
class ProductB2 implements ProductB {
@Override
publicvoid method1() {
System.out.println("等级为2的产品B的逻辑");
}
@Override
publicvoid method2() {
// 业务逻辑处理代码
}
// 更多产品逻辑.....
}
// 抽象工厂接口
interface AbstractFactory {
public ProductA createProductA();
public ProductB createProductB();
// 更多创建产品.....
}
// 具体工厂1:创建等级为1的A、B产品
class ConcreateFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
returnnew ProductA1();
}
@Override
public ProductB createProductB() {
returnnew ProductB1();
}
// 更多代码逻辑......
}
// 具体工厂1:创建等级为2的A、B产品
class ConcreateFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
returnnew ProductA2();
}
@Override
public ProductB createProductB() {
returnnew ProductB2();
}
// 更多代码逻辑......
}
// 客户端
publicclass Client {
publicstaticvoid main(String[] args) {
// 定义两个工厂,等级为1和等级为2
ConcreateFactory1 factory1 = new ConcreateFactory1();
ConcreateFactory2 factory2 = new ConcreateFactory2();
// 定义不同等级的A产品
ProductA a1 = factory1.createProductA();
ProductA a2 = factory2.createProductA();
// 定义不同等级的B产品
ProductB b1 = factory1.createProductB();
ProductB b2 = factory2.createProductB();
// 调用产品的业务逻辑
a1.method1();
b1.method1();
a2.method1();
b2.method1();
// 更多业务逻辑....
}
}
运行结果:
等级为1的产品A的逻辑
等级为1的产品B的逻辑
等级为2的产品A的逻辑
等级为2的产品B的逻辑
应用场景例子:
抽象工厂的优点不言而喻,下面我们以耐克体育运动品牌为例子加以巩固。我们知道,耐克是一个体育用品生产商,并且我们也很熟悉耐克运动装和运动鞋。假设耐克只是生产运动装和运动鞋,并且运动装有专业档次的和普通档次的,当然不同的档次的价格和材料不同,同样运动鞋也有不同档次的,不同档次的价格和材料也不同,这样耐克生产的产品如下:
//NIKE运动鞋
interface INIKESportsShoes {
public String getShoesInfo();
public Double getShosePrice();
}
//NIKE运动装
interface INIKESportswear {
public String getSportswearInfo();
public Double getSportswearPrice();
}
//Nike专业运动鞋
class NikeSpecialSportsShoes implements INIKESportsShoes {
@Override
public String getShoesInfo() {
return"原装进口,拥有高强度防滑和脚部保护特性";
}
@Override
public Double getShosePrice() {
return 8888.99;
}
}
//Nike 普通运动鞋
class NikeNormSportsShoes implements INIKESportsShoes {
@Override
public String getShoesInfo() {
return"Made in China,一般防滑和脚步保护";
}
@Override
public Double getShosePrice() {
return 489.99;
}
}
//Nike 专业运动装
class NikeSpecialSportswear implements INIKESportswear {
@Override
public String getSportswearInfo() {
return"原装进口,高强度防刮防擦破和四肢防护功能并提供夜晚荧光功能";
}
@Override
public Double getSportswearPrice() {
return 9998.99;
}
}
//Nike 普通运动装
class NikeNormSportswear implements INIKESportswear {
@Override
public String getSportswearInfo() {
return"Made in China,一般防雨和防晒特性";
}
@Override
public Double getSportswearPrice() {
return 998.88;
}
}
//NIKE运动产品
interface INIKESportProduct {
public INIKESportsShoes getNikeSportsShoes();
public INIKESportswear getNikeSportswear();
}
//Nike 专业运动产品
class NikeSpecialSportProduct implements INIKESportProduct {
@Override
public INIKESportsShoes getNikeSportsShoes() {
returnnew NikeSpecialSportsShoes();
}
@Override
public INIKESportswear getNikeSportswear() {
returnnew NikeSpecialSportswear();
}
}
//Nike 普通运动产品
class NikeNormSportProduct implements INIKESportProduct {
@Override
public INIKESportsShoes getNikeSportsShoes() {
returnnew NikeNormSportsShoes();
}
@Override
public INIKESportswear getNikeSportswear() {
returnnew NikeNormSportswear();
}
}
//一次去Nike专营店购买Nike产品的经历
publicclass BuyNikeProduct {
publicstaticvoid main(String[] args) {
// 实例化Nike体育产品
INIKESportProduct NikeSpecialSportProduct = new NikeSpecialSportProduct();
INIKESportProduct NikeNormSportProduct = new NikeNormSportProduct();
// 买一件Nike专业运动装
INIKESportswear NikeSpecialSportswear = NikeSpecialSportProduct
.getNikeSportswear();
// 买一件普通的Nike运动鞋
INIKESportsShoes NikeNormSportShoes = NikeNormSportProduct
.getNikeSportsShoes();
// 看看产品状况
System.out.println(”专业运动装:“+NikeSpecialSportswear.getSportswearInfo());
System.out.println("普通运动鞋:"+NikeNormSportShoes.getShoesInfo());
// 计算一下价格准备付款
System.out.println("先生,价格是:");
Double price = NikeSpecialSportswear.getSportswearPrice()
+ NikeNormSportShoes.getShosePrice();
System.out.println(NikeSpecialSportswear.getSportswearPrice() + "+"
+ NikeNormSportShoes.getShosePrice() + " 共 " + price
+ " 付现金还是刷卡?");
System.out.println("My God ! You know what will happen!");
}
}
购物结果:
专业运动装:原装进口,高强度防刮防擦破和四肢防护功能并提供夜晚荧光功能
普通运动鞋:Made in China,一般防滑和脚步保护
先生,价格是:
9998.99+489.99 共 10488.98 付现金还是刷卡?
My God ! You know what will happen!
从抽象工厂的UML图和例子代码分析总结出其优缺点如下:
抽象工厂的优点:
-
具体产品从客户代码中被分离出来
-
容易改变产品的系列
将一个系列的产品族统一到一起创建
抽象工厂的缺点:
对于新增加的产品,无能为力,支持增加产品族, 在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口。比如Nike产品增加了运动穿戴设备如智能手表该怎么办?只能重构产品族了。
------------------
写到这,又不觉叹息,又到周日了,眼看着马上就要上班了。但是,据说这一次有个小帮手来帮我干活,想到这,还是不午睡了,虽然已经下午17:21分了。