抽象工厂模式是常用的创建型模式之一,它比工厂方法模式的抽象程度更高。在工厂方法模式中,每一个具体工厂只需要生产一种具体产品,但是在抽象工厂模式中,一个具体的工厂可以生产一组相关的具体产品,这样的一组产品称为产品族,产品族中的每一个产品都分属于某一个产品继承等级结构。
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个具体工厂只有一个或者一组重载的工厂方法,只能生产一种产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。
抽象工厂的概述
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。
抽象工厂的定义
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式的结构
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂) : 它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品): 它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
-
ConcreteProduct(具体产品): 它定义具体工厂生产的及具体产品对象,实现抽象产品接口中声明的业务方法。
抽象工厂的实现
例如上述代码结构,1部分,包含了抽象工厂,抽象产品,2部分包含了具体工厂,具体产品。当有新的工厂需要加入时,只需要扩展2部分即可。
例如Excel的操作:
抽象工厂:
public interface AbstractExcelFactory
{
public AbstractProductWriteExcel CreateProductWrite(); // 工厂方法一
public AbstractProductSetStyle CreateProductSetStyle(); // 工厂方法一
}
抽象产品1, 给Excel设置样式:
public interface AbstractProductSetStyle
{
public void SetStyle();
}
抽象产品2, 给Excel写入文本:
public interface AbstractProductWriteExcel
{
public void WriteExcel();
}
具体工厂,NPOI:
public class ConcreteFactoryNPOI : AbstractExcelFactory
{
public AbstractProductSetStyle CreateProductSetStyle()
{
return new ConcreteProductNPOISetStyle();
}
public AbstractProductWriteExcel CreateProductWrite()
{
return new ConcreteProductNPOIWrite();
}
}
具体产品, NPOI设置样式:
public class ConcreteProductNPOISetStyle : AbstractProductSetStyle
{
public void SetStyle()
{
Console.WriteLine("NPOI set style.");
}
}
具体产品, NPOI写入文本:
public class ConcreteProductNPOIWrite : AbstractProductWriteExcel
{
public void WriteExcel()
{
Console.WriteLine("NPOI write excel.");
}
}
调用方式:
// 抽象工厂
AbstractExcelFactory factory;
factory = new ConcreteFactoryNPOI(); // 此处可可使用配置文件+反射获取
var setStyleProduct = factory.CreateProductSetStyle();
setStyleProduct.SetStyle();
var writeProduct = factory.CreateProductWrite();
writeProduct.WriteExcel();
抽象工厂的优点
- 隔离了具体类的生成
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族很方便,无须修改已有系统,符合开闭原则。
抽象工厂的缺点
增加新的产品等级结构麻烦,需要对原有的系统进行较大的修改,甚至需要修改抽象层代码,这显然带来较大的不便,违背了开闭原则。例如上述代码中,如果添加一个设置公式的产品功能,就需要从最顶层开始修改。
抽象工厂的使用环境
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
- 系统中有多于一个的产品族,但每次只使用其中某一产品族
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构