工厂方法模式(Factory Method Pattern)

一、什么是工厂方法模式

工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

在Factory Method模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

 

 

二、工厂方法模式的结构与角色

  • 抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
  • 具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
  • 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
  • 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。

 

 

三、工厂方法模式与简单工厂模式

  1. 工厂方法模式与简单工厂模式再结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
  2. 工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
  3. 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了"开放-封闭"原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
  4. 工厂方法模式退化后可以演变成简单工厂模式。

 

四、工厂方法模式的实现要点

  • Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现;二是Creator是一个具体的类且它提供一个工厂方法的缺省实现。
  • 工厂方法是可以带参数的。
  • 工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。

 

 

五、工厂方法模式的效果

  • 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。
  • Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。

 

 

六、工厂方法模式的适用性

在以下情况下,适用于工厂方法模式:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

 

 

七、工厂方法模式的应用实例

需求现在我们考虑一个日志记录的例子(这里我们只是为了说明Factory Method模式,实际项目中的日志记录不会这么去做,也要比这复杂一些)。假定我们要设计日志记录的类,支持记录的方法有FileLogEventLog两种方式。

1、首先定义一个Log的抽象类,也就是抽象产品(Product)角色

1 //抽象产品(所以Log产品的父类)
2 public abstract class Log
3 {
4 public abstract void Write(); //定义一个记录日志的方法
5 }

2、定义一个EventLog类和FileLog类,也就是具体产品(Concrete Product)角色

 1 //操作日志(继承自Log类,抽象产品)
2 public class EventLog : Log
3 {
4 public override void Write()
5 {
6 Console.WriteLine("Write a event log.");
7 }
8 }
9
10 //文件日志(继承自Log类,抽象产品)
11 public class FileLog : Log
12 {
13 public override void Write()
14 {
15 Console.WriteLine("Write a file log.");
16 }
17 }

3、定义一个IFactory的接口,也就是抽象工厂(Creator)角色,她是工厂方法模式的核心

1 //抽象工厂(所有的具体工厂类都要实现这个接口)
2 public interface IFactory
3 {
4 Log CreateLog(); //创建相应的产品
5 }

4、创建EventLogFactory类和FileLogFactory类,这两个类都必须实现抽象工厂(IFactory接口),这就是具体工厂(Concrete Creator)角色

 1 //操作日志工厂(实现IFactory接口,抽象工厂)
2 public class EventLogFactory : IFactory
3 {
4 public Log CreateLog()
5 {
6 return new EventLog();
7 }
8 }
9
10 //文件日志工厂(实现IFactory接口,抽象工厂)
11 public class FileLogFactory : IFactory
12 {
13 public Log CreateLog()
14 {
15 return new FileLog();
16 }
17 }

5、最后看一下客户端代码

 1 public class Client
2 {
3 public static void Main(string[] args)
4 {
5 IFactory factory = new EventLogFactory();
6 Log log = factory.CreateLog();
7 log.Write();
8
9 Console.Read();
10 }
11 }

在客户程序中,我们有效地避免了具体产品对象和应用程序之间的耦合,可是我们也看到,增加了具体工厂对象和应用程序之间的耦合。那这样究竟带来什么好处呢?我们知道,在应用程序中,Log对象的创建是频繁的,在这里我们可以把

1 LogFactory factory = new EventFactory();

这句话放在一个类模块中,任何需要用到Log对象的地方仍然不变。要是换一种日志记录方式,只要修改一处为:

1 LogFactory factory = new FileFactory();

其余的任何地方我们都不需要去修改。有人会说那还是修改代码,其实在开发中我们很难避免修改,但是我们可以尽量做到只修改一处。

 

posted @ 2012-04-08 22:25  技术勇者  阅读(488)  评论(0编辑  收藏  举报