设计模式之工厂模式
定义
抽象工厂模式(Abstract Factory Pattern)隶属于设计模式中的创建型模式,用于产品族的构建。抽象工厂是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
工厂模式中的每一个形态都是针对一定问题的解决方案,工厂方法针对的是多个产品系列结构;而抽象工厂模式针对的是多个产品族结构,一个产品族内有多个产品系列。
角色
- 抽象产品
- 具体产品
- 抽象工厂
- 具体工厂
分类
工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。
简单工厂
IUpRd1.png我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
在简单工厂模式中创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。
简单来说,简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。简单工厂模式不在 GoF 23 种设计模式之列。
简单工厂模式每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,违背了“开闭原则”
例子
- 抽象产品
public interface Product {
void function();
}
- 具体产品A
public class AConcreteProduct implements Product {
@Override
public void function() {
System.out.println("A product function.........");
}
}
- 具体产品B
public class BConcreteProduct implements Product{
@Override
public void function() {
System.out.println("B product function.........");
}
}
- 简单工厂
public class SimpleFactory {
public static Product create(String param){
if ("A".equals(param)){
return new AConcreteProduct();
}
return new BConcreteProduct();
}
}
- 测试
public class Test {
public static void main(String[] args) {
Product a = SimpleFactory.create("A");
a.function();
}
}
-----------------------------------------------------------------------------------
A product function.........
Process finished with exit code 0
-----------------------------------------------------------------------------------
利弊
优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
缺点:
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
- 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
应用场景
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
工厂方法
简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
结构图
IUPKaR.png把简单工厂模式中的工厂转成每个产品自有的工厂,原本工厂类创建产品的责任划分到了具体产品的工厂类身上。
例子
- 产品和具体产品
public interface Product {
void function();
}
public class AConcreteProduct implements Product {
@Override
public void function() {
System.out.println("A product function.........");
}
}
public class BConcreteProduct implements Product {
@Override
public void function() {
System.out.println("B product function.........");
}
}
- 抽象工厂类
public interface AbstratctFactory {
Product create();
}
- 具体工厂类
public class AProductFactory implements AbstratctFactory {
@Override
public Product create() {
return new AConcreteProduct();
}
}
public class BProductFactory implements AbstratctFactory {
@Override
public Product create() {
return new BConcreteProduct();
}
}
- 测试
public class Test {
public static void main(String[] args) {
AProductFactory factory = new AProductFactory();
Product product = factory.create();
product.function();
}
}
-----------------------------------------------------------------------------------
A product function.........
利弊
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌
抽象工厂
工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
结构图
IUVqeO.png从图 可以看出抽象工厂模式的结构同工厂方法模式的结构相似,不同的是其产品的种类不止一个,所以创建产品的方法也不止一个。下面给出抽象工厂和具体工厂的代码。
例子
工程师安装电脑,主板和CPU有Intel和Amd两种,AMD有AMD的工厂生产AMD的主板和CPU,Intel的工厂生产Intel的主板和CPU
- 抽象产品CPU和主板
public interface Cpu {
void calculate();
}
public interface MainBoard {
void installCpu();
}
- 具体的AMD的CPU和Intel的CPU
~~~java
public class AmdCpu implements Cpu {
@Override
public void calculate() {
System.out.println("AMD Cpu run..........");
}
}
public class IntelCpu implements Cpu {
@Override
public void calculate() {
System.out.println("Intel Cpu run..........");
}
}
- 具体的AMD主板和Intel主板
public class AmdMainBoard implements MainBoard {
@Override
public void installCpu() {
System.out.println("adm 主板安装中........");
}
}
public class IntelMainBoard implements MainBoard {
@Override
public void installCpu() {
System.out.println("Intel 主板安装中.........");
}
}
- 抽象工厂生产CPU和主板
public interface AbstractFacotry {
Cpu createCpu();
MainBoard installMainBoard();
}
- 具体的AMD工厂和Intel工厂
public class AmdFactory implements AbstractFacotry {
@Override
public Cpu createCpu() {
return new AmdCpu();
}
@Override
public MainBoard installMainBoard() {
return new AmdMainBoard();
}
}
public class IntelFactory implements AbstractFacotry {
@Override
public Cpu createCpu() {
return new IntelCpu();
}
@Override
public MainBoard installMainBoard() {
return new IntelMainBoard();
}
}
- 工程师组装电脑,安装主版和CPU
public class ComputerEngineer {
public void makeComputer(AbstractFacotry cf) {
MainBoard mainBoard = cf.installMainBoard();
Cpu cpu = cf.createCpu();
mainBoard.installCpu();
cpu.calculate();
}
}
- 测试
public class FactoryTest {
public static void main(String[] args) {
ComputerEngineer computerEngineer = new ComputerEngineer();
IntelFactory intelFactory = new IntelFactory();
computerEngineer.makeComputer(intelFactory);
}
}
-----------------------------------------------------------------------------------
Intel 主板安装中.........
Intel Cpu run..........
利弊
抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。
- 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
- 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
- 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
其缺点是:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。