简介
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。这种模式使得对象的创建延迟到子类,从而实现了对扩展开放、对修改关闭的原则。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。
优点
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
- 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
缺点
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
应用场景
- 灵活性和可扩展性:当需要一个框架能够灵活地、可扩展地处理多种产品时,工厂方法模式是一个合适的选择。例如,在设计一个连接邮件服务器的框架时,如果有多种网络协议可供选择,如POP3、IMAP、HTTP,可以将这些连接方法作为产品类,通过工厂方法根据不同的条件选择不同的连接方式,从而实现完美的扩展性。
- 异构项目交互:工厂方法模式也适用于异构项目交互。例如,通过WebService与一个非Java项目交互时,可以将从WSDL中产生的对象视为产品,由一个具体的工厂类进行管理,减少与外围系统的耦合。
- 测试驱动开发:在测试驱动开发的框架下,工厂方法模式可以用来虚拟出与被测试类有关联关系的类,避免这些类之间的耦合。例如,测试一个类A时,可以使用工厂方法模式来创建与类A关联的类B的虚拟实例。
- 多种专卖店的情况:在实际生活中,如果有多个专卖店,每家专卖店销售的电脑品牌不同,可以使用工厂方法模式来处理这种情况。每个专卖店(超类)可以有多个子类,每个子类决定提供什么型号的电脑。这样,当需要购买电脑时,可以通过相应的工厂类来获取特定品牌和型号的电脑。
实现
通过一个案例来演示工厂方法模式:使用工厂方法模式设计一个程序来读取各种不同类型的文件,针对每一种文件都设计一个文件读取器,如office文件读取器用于读取office格式的文件、PDF文件读取器用于读取PDF格式的文件。需充分考虑系统的灵活性和可扩展性。
- 定义抽象产品类(文件接口):
/// <summary>
/// 文件接口类
/// </summary>
public interface IFile
{
void GetFiles();
}
- 具体产品实现类:
/// <summary>
/// 产品类:Office文件
/// </summary>
public class OfficeFile : IFile
{
public void GetFiles()
{
Console.WriteLine("获取Office类型文件!");
}
}
/// <summary>
/// 产品类:PDF文件
/// </summary>
public class PDFFile : IFile
{
public void GetFiles()
{
Console.WriteLine("获取PDF文件!");
}
}
- 定义抽象工厂类:
/// <summary>
/// 文件抽象工厂类
/// </summary>
public interface IFileFactory
{
IFile GetFileList();
}
- 具体产品工厂类:
/// <summary>
/// 产品工厂:Office文件
/// </summary>
public class OfficeFactory : IFileFactory
{
public IFile GetFileList()
{
return new OfficeFile();
}
}
/// <summary>
/// 产品工厂:PDF文件
/// </summary>
internal class PDFFactory : IFileFactory
{
public IFile GetFileList()
{
return new PDFFile();
}
}
- 上层应用调用:
{
//获取Office文件
IFileFactory fileFactory = new OfficeFactory();
IFile file = fileFactory.GetFileList();
file.GetFiles();
}
{
//获取PDF文件
IFileFactory fileFactory = new PDFFactory();
IFile file = fileFactory.GetFileList();
file.GetFiles();
}