工厂方法模式
# 分类
创建型模式
# 定义
工厂方法模式(Factory Methond Pattern) 这种模式提供了一种创建对象的方式,在工厂方法模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且通过使用一个共同的接口来指向新创建的对象。
# 意图
工厂方法模式定义一个创建对象的接口,让其子类自己决定实例化哪个具体类
,工厂方法模式使其创建过程延迟到子类进行。
# 应用场景
- 客户程序需要
隔离
它与需要创建的具体类型
间的耦合关系。 - 很多情况下,客户程序在开发过程中还
无法预知
生产环境中实际要提供给客户程序创建的具体类型
。 - 将创建具体实例工作隔离在客户程序之外,
客户程序仅需要执行自己的业务逻辑
,把这部分职责交给外部对象完成。 - 如果目标对象虽然可以统一抽象为某个抽象类型,但它们的
继承关系太过复杂
,层次性比较复杂,这时同样可以通过工厂方法解决这个问题。
应用案例
- 你需要一辆汽车,可以直接从工厂里提货,而不是去管这辆车是怎么造出来的,以及这个车里面的具体实现。
- 数据库访问:当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,“POP3”,"IMAP","HTTP",可以把这三个作为产品类,共同实现一个接口。
# 角色与结构图
- Product:
抽象产品角色
工厂要加工的对象所具有的抽象特征实体。 - Concrete Product:
具体产品角色
实现客户程序所需要的抽象特质的类型,它是工厂需要延迟实例的备选对象。 - Factory:
抽象工厂角色
定义一个工厂方法的默认实现,它返回抽象产品类型 Product。 - ConcreteFactory:
具体工厂角色
具体产品类型 Concrete Product的具体工厂,方法用来生成具体产品。 - Client:
客户程序
作为 Product 消费者的时候,抽象类在构造实例的时候到底将其"挂"在哪个实体类型由 Concrete Factory 决定。
下图解释了工厂方法模式中各角色的作用

# 示例代码
//抽象产品类型
public interface IProduct
{
// 约定的抽象产品所必须具有的特征
string Name { get;}
}
// 具体产品类型
public class ProductA : IProduct
{
public string Name { get { return "A"; } }
}
public class ProductB : IProduct
{
public string Name { get { return "B"; } }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 一个系列的工厂,生产一个系列的产品
public interface IFactory
{
// 每个工厂所需要具有的工厂方法——创建产品
IProduct Create();
}
// A工厂创建A产品
public class FactoryA : IFactory
{
public IProduct Create()
{
return new ProductA();
}
}
// B工厂创建B产品
public class FactoryB : IFactory
{
public IProduct Create()
{
return new ProductB();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 客户程序
class Client
{
public static void Main(string[] args)
{
IFactory factory = new FactoryA();
IProduct product = factory.Create();
product.Use();
}
}
2
3
4
5
6
7
8
9
10
# 优点
- 一个调用者想创建一个对象,只要知道
具体工厂的名称
就可以了。 - 扩展性高,如果想要增加一个产品,只要扩展
一个工厂类
和一个产品类
就可以。 屏蔽产品的具体实现
,调用者只关心产品的接口。
# 缺点
- 每次增加一个产品时,都需要增加
一个具体产品类
和一个具体工厂类
,使得系统中类的个数成倍增长
,在一定程度上增加了系统的复杂度
,同时也增加了系统具体类的依赖,这并不是好事。
# 小结
直观上客户程序可以把频繁变化的某个 Product 隔离在自己的视线之外,自身不会受到它的影响。
工厂方法给我们设计应用一个很好的
模式化new()思维
,通过引入新的对象,在很大程度上解放了客户程序对具体类型的依赖,其方法就是将具体产品对象延迟构造到子类,但依赖关系是始终存在的,解放一个对象的时候等于把麻烦转嫁到另一个对象上。为此,工程中往往最后把推不掉的依赖关系推到配置文件上,也就是推到.NET Framework 上,这样工厂方法模式往往在项目中被演绎成“工厂方法 + 依赖注入 + 配置文件访问”
的组合方式。主要解决?主要解决接口选择的问题。
何时使用?我们明确地计划不同条件下创建不同实例时。
如何解决?让其子类实现工厂接口,返回的也是一个抽象产品。
关键代码?创建过程在其子类执行。
# 大结
耦合关系直接决定着软件面对变化时的行为。 模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之更改。 模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其他模块保持不变。 软件的变化如果不大。使用紧耦合也能很好高效的工作,如果软件变化频繁,则需要使用设计模式的松耦合来组织。
软件系统的主逻辑应该是变动较小的,如果主逻辑都在剧烈变化,那么软件就相当不稳定。
动机:在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是他却拥有比较稳定的接口。 如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖该对象的对象”不随着需求改变而改变。 意图:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使得一个类的实例化延迟到子类。
# 一句话概括
一个工厂类根据创建与其对应的产品实例。比如:汽车工厂创建汽车。