1. 意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
2.别名
虚构造器 Virtual Constructor
3. 适用性
当一个类不知道它所必须创建的对象的类的时候
当一个类希望由它的子类来指定它所创建的对象的时候
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候
工厂方法很简单,但是却是常被误解的一个模式。
首先,这个模式叫 Factory Method, Factory表明它是一个创建型模式,而Method表明这个模式的重点就是那个"Method' (方法), 看别名就知道 - Virtual Constructor
其次,很多人以为Factory Method就是用一个带有参数的方法通过条件判断来返回不同的子类,这种认识是片面的
第三,由于抽象工厂(Abstract Factory)与工厂方法(Factory Method) 都带 ”工厂(Factory)"这个字眼,很多人搞不清他们的区别。抽象工厂是Kit,重点是 Factory, 工厂方法是Virtual Constructor,重点是 Method
4.类图
5. 实例
.NET Framework中有一个很好的例子
public abstract class DbConnection : Component, IDbConnection, IDisposable { ... public DbCommand CreateCommand() { return this.CreateDbCommand(); } protected abstract DbCommand CreateDbCommand(); ... }
CreateCommand 方法需要一个DBCommand的实例,但是由于DBCommand是抽象类,基于依赖倒置原则这里不能指定具体要创建子类的类型,因此定义了一个抽象方法去创建这个对象
这个抽象方法就是 Factory Method 的 “method" !
当子类SqlConnection去重载这个方法的时候,会创建一个SqlCommand的实例(SqlCommand继承DBCommand)
这就是“让子类决定实例化哪一个类"
6. 工厂方法的两种不同的情况
Gof书中提到工厂方法主要有两种不同的情况
1) Creator类是一个抽象类并且不提供它所生命的工厂方法的实现 (就是5中的例子)
2) Creator类是一个具体的类并且为工厂方法提供一个缺省的实现
7. 参数化工厂方法
设计模式一书中提到的参数化工厂方法的意图是工厂方法通过一个参数来创建具体的对象, 当然子类可以更改这些行为提供更多的灵活性。
由于有些时候我们不需要这么大的灵活性,因此就没有子类来重载工厂方法
下面的代码就是一个例子
class Program { static void Main(string[] args) { Console.WriteLine(GetProduct("A").ToString()); } static AbstractProduct GetProduct(string type) { if (type == "A") return new ProductA(); else if (type == "B") return new ProductB(); else throw new NotSupportedException("invalid type"); } } abstract class AbstractProduct { } class ProductA : AbstractProduct { } class ProductB : AbstractProduct { }
其中 GetProduct()就是工厂方法,这个例子中Creator没有子类
有时候为了体现单一职责原则,或者出于重用的目的我们会将工厂方法放到一个独立的类中
class ProductFactory { public static AbstractProduct GetProduct(string type) { if (type == "A") return new ProductA(); else if (type == "B") return new ProductB(); else throw new NotSupportedException("invalid type"); } }
这种形式可能是很多初学者所熟悉的,要注意通常这种独立类提供的工厂方法一般是 static
另外不要把参数化的工厂方法和Strategy模式搞混。
Strategy模式的调用者可以通过一个提供默认实现的工厂方法来返回具体的算法