工厂方法模式是设计模式中的一种创建型模式,由著名的四人帮(Gang Of Four,GoF)在其著作中提出。工厂方法模式的定义是:“定义一个用于创建对象的接口,但让子类决定要实例化的类。工厂方法让一个类推迟实例化到子类。”为了更清楚地理解这个定义,将通过本文的各个部分来逐步解析。
将继续使用第一部分中的例子,以便能够理解当应用程序增长时会出现哪些类型的问题,以及何时应该使用工厂方法模式(因为每种模式都有自己的位置、优势和限制)。
首先,定义了一个名为IFan的接口,它包含两个方法:
interface IFan {
void SwitchOn();
void SwitchOff();
}
最初,公司打算只创建三种类型的风扇:台扇、吊扇和排风扇。所有风扇都将具有SwitchOn()和SwitchOff()方法,它们的实现可能会有所不同。让使用相同的类并实现IFan接口。
class TableFan : IFan {...}
class CeilingFan : IFan {...}
class ExhaustFan : IFan {...}
到目前为止,编写的代码与“简单工厂模式”示例中的代码相同。
当实现工厂方法模式时,需要遵循其设计,如下所示:
根据定义,“定义一个用于创建对象的接口...”,所以让定义一个接口,它将包含一个创建风扇的方法。在子类中实现这个方法将具有创建具体对象的逻辑。
interface IFanFactory {
IFan CreateFan();
}
注意:使用了IFanFactory接口,但也可以改用抽象类。抽象类需要至少有一个未实现的抽象方法,该方法将在子类中实现以创建对象。
继续定义:“...让子类决定要实例化的类...”:让创建子类,这些子类将决定将使用哪个具体类来创建实例。为了创建三种类型的对象,即TableFan、CeilingFan和ExhaustFan,需要创建三种类型的工厂或IFanFactory的子类。这些三个工厂将实现IFanFactory接口。
class TableFanFactory : IFanFactory {...}
class CeilingFanFactory : IFanFactory {...}
class ExhaustFanFactory : IFanFactory {...}
继续定义:“...工厂方法让一个类推迟实例化到子类。”:在这里,IFan CreateFan()是一个工厂方法。在具体工厂(TableFanFactory等)中的CreateFan方法(即工厂方法)内部,指定将实例化哪个确切的类以创建风扇对象。因此,IFanFactory将其子类(即TableFanFactory、CeilingFanFactory和ExhaustFanFactory)推迟决策具体类。
以下是客户端实现的示例:
static void Main(string[] args) {
IFanFactory fanFactory = new PropellerFanFactory();
// 使用工厂方法模式创建风扇
IFan fan = fanFactory.CreateFan();
// 使用创建的对象
fan.SwitchOn();
Console.ReadLine();
}
在上面的例子中,为了创建三种类型的对象(TableFan、CeilingFan和ExhaustFan),创建了三个工厂类,而在学习“简单工厂模式”时,只创建了一个工厂。这是因为遵循了工厂方法模式的规则。现在问题来了,为什么需要使用工厂方法模式,因为已经可以通过“简单工厂模式”实现相同的功能。
假设公司即将推出一种名为“PropellerFan”的新风扇。这是新的需求。使用工厂方法模式,不需要像在“简单工厂模式”中那样添加新的条件,而只需创建一个名为“PropellerFan”的新类,并使其继承IFan接口,就像为其他风扇所做的那样。
class PropellerFan : IFan {.....}
然后,将创建一个新的工厂名为PropellerFanFactory,并使其继承自IFanFactory。每当客户端想要创建PropellerFan类的实例时,只需创建PropellerFanFactory的实例,客户端就可以获得PropellerFan的实例。
在上一节中,看到了工厂方法模式遵循开闭原则。当新需求到来时,不需要修改现有代码,而只需要创建一个额外的工厂。
与简单工厂模式相比,使用工厂方法模式编写单元测试用例更容易,因为不使用switch-case(或长if-else块)。
为了支持额外的产品,不需要修改现有代码,只需要添加一个新的工厂类,因此不需要重新运行现有的旧单元测试。
客户端调用CreateFan(工厂方法),而不知道如何以及实际创建的对象类型是什么。