大千世界,茫茫人海,相识就是一种缘分。若此篇文章对您有帮助,点个赞或点个关注呗!
前言
在了解每一种设计模式之前,我们都应该大体了解设计模式的具体分类以及不同设计模式的重要等级。设计模式的整体归类,已在第一篇Java设计模式中做出归类总结。点击查阅
继上一篇文章:【Java设计模式】系列二:工厂方法模式
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性。一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以创建多个产品对象,而不是单一的产品对象,这里需要引入抽象工厂的设计模式。
✍为了更清晰地理解抽象工厂设计模式,需要先引入两个概念:
- 产品等级结构: 产品等级结构及产品的继承结构,如一个抽象类是汽车,其子类有路虎揽胜、大众途锐、本田URV,则抽象汽车与具体品牌的汽车之间构成了一个产品等级结构。抽象汽车是父类,而具体品牌的汽车是其子类。
- 产品族: 在抽象工厂模式中,产品族是指一个工厂生产的,位于不同产品等级结构中的一组产品,如何路虎工厂生产的揽胜运动版汽车、路虎星脉、路虎极光、路虎发现位于汽车等级结构中。
✍如果上面文字看不懂,也没关系,产品等级结构与产品族图示:
相同颜色的代表同一产品等级
相同形状,不同颜色的是一个产品族
比如说路虎厂商,还路虎揽胜品牌汽车,旗下还有路虎星脉品牌汽车,路虎厂商生产的所有都是属于路虎的品牌,都会悬挂路虎统一车标,属于同一产品等级。
向上箭头的是 一个个具体工厂
✍对这些概念有了解之后,会发现抽象工厂的动机很简单:
- 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是 多个位于不同产品等级结构中属于不同类型的具体产品时,需要使用抽象工厂模式。
- 抽象工厂模式是所有形式的工厂模式中,最为抽象和最具一般性的一种形态 。
- 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
✍ 这里引出抽象工厂的定义:
抽象工厂模式(Abstract Factory Pattern) : 提供一个创建一系列相关或相互依赖对象的接口 ,而无须指定它们具体的类 。抽象工厂模式又称为Kit 模式 ,属于对象创建型模式。
抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
从设计层面看,抽象工厂模式就是对简单工厂模式的改造(或者进一步的抽象)。将工厂抽象成两层(AbsFactory抽象工厂和具体实现的工厂子类)。开发者可以根据创建对象类型使用相应的工厂子类,这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展。
抽象工厂模式包含如下角色:
- AbstractFactory: 抽象工厂,提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- ConcreteFactory: 具体工厂,主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- AbstractProduct: 抽象产品,定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- Product: 具体产品,实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
✍ 具体代码示例:
创建CarFactory接口(AbstractFactory:抽象工厂)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 12:23
*/
public interface CarFactory {
DzCar getDzCar();
LuCar getLuCar();
}
创建DzCar抽象类(AbstractProduct:抽象产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 10:33
*/
public abstract class DzCar {
public abstract void produceCar();
}
创建LuCar抽象类(AbstractProduct:抽象产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 10:33
*/
public abstract class LuCar {
public abstract void produceCar();
}
创建ConcreteOneFactory 类一(ConcreteFactory:具体工厂)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:19
*/
public class ConcreteOneFactory implements CarFactory {
@Override
public DzCar getDzCar() {
return new DzTrCar();
}
@Override
public LuCar getLuCar() {
return new LuLsCar();
}
}
创建DzTaCar类(Product:具体产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:16
*/
public class DzTrCar extends DzCar{
@Override
public void produceCar() {
System.out.println("生产【大众】途锐汽车!");
}
}
创建LuLsCar类(Product:具体产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:17
*/
public class LuLsCar extends LuCar {
@Override
public void produceCar() {
System.out.println("生产【路虎】揽胜汽车!");
}
}
创建ConcreteTwoFactory类二(ConcreteFactory:具体工厂)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:19
*/
public class ConcreteTwoFactory implements CarFactory {
@Override
public DzCar getDzCar() {
return new DzTaCar();
}
@Override
public LuCar getLuCar() {
return new LuXmCar();
}
}
创建DzTaCar类(Product:具体产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:22
*/
public class DzTaCar extends DzCar {
@Override
public void produceCar() {
System.out.println("生产【大众】途昂汽车!");
}
}
创建LuXmCar 类(Product:具体产品)
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:23
*/
public class LuXmCar extends LuCar {
@Override
public void produceCar() {
System.out.println("生产【路虎】星脉汽车!");
}
}
创建测试类TestCar
package com.bnl.facoryMethod;
/**
* @Author:bnli
* @Date:2020/3/7 13:26
*/
public class TestCar {
public static void main(String[] args) {
CarFactory factoryOne = new ConcreteOneFactory();
DzCar dzCar = factoryOne.getDzCar();
LuCar luCar = factoryOne.getLuCar();
dzCar.produceCar();
luCar.produceCar();
System.out.println("----------------------------------------------------");
CarFactory factoryTwo = new ConcreteTwoFactory();
DzCar dzCar1 = factoryTwo.getDzCar();
LuCar luCar1 = factoryTwo.getLuCar();
dzCar1.produceCar();
luCar1.produceCar();
}
}
测试结果:
生产【大众】途锐汽车!
生产【路虎】揽胜汽车!
----------------------------------------------------
生产【大众】途昂汽车!
生产【路虎】星脉汽车!
Process finished with exit code 0
✍转成UML图:
✍通过UML图,可以很清晰的查阅整体创建过程 分析总结
抽象工厂模式的优点:
- 抽象工厂模式隔离了具体产品类的创建,创建者无需知道创建具体产品类的流程。由于这种创建,更换一个具体工厂就变得相对容易。所有具体工厂都实现了抽象工厂中定义的公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个系统的行为。符合Java的编程思想【高内聚低耦合】。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
抽象工厂模式的优点:
- 在添加新的产品对象,比如创建丰田品牌的汽车(getFtCar())。此时难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,若要新增新产品对象,就必须对抽象接口进行扩充,而则将涉及到具体抽象工厂及其所有子类都必须修改,牵一发动全身。
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)
✍谈完抽象工厂的优缺点,我们在谈谈抽象工厂的应有场景,这也是面试官面试的高频点
-
其实JDK中的Calender类中,就使用了工厂模式,只不过是简单工厂模式
✍关于抽象工厂的拓展: -
“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
(1) 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
(2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。 -
抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便