工厂方法工厂方法模式(英語:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体類別的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的類別来决定实例化哪个類別。工厂方法让類別的实例化推迟到子類別中进行。”[1] 创建一个对象常常需要复杂的过程,所以不适合包含在一个复合对象中。创建对象可能会导致大量的重复代码,可能会需要复合对象访问不到的信息,也可能提供不了足够级别的抽象,还可能并不是复合对象概念的一部分。工厂方法模式通过定义一个单独的创建对象的方法来解决这些问题。由子類別实现这个方法来创建具体類別的对象。 对象创建中的有些过程包括决定创建哪个对象、管理对象的生命周期,以及管理特定对象的建立和销毁的概念。 工厂在面向对象程序设计中,工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。 工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种類別的对象。这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象。 有时,特定類別对象的控制过程比简单地创建一个对象更复杂。在这种情况下,工厂对象就派上用场了。工厂对象可能会动态地创建产品類別的对象,或者从对象池中返回一个对象,或者对所创建的对象进行复杂的配置,或者应用其他的操作。 这些類別的对象很有用。几个不同的设计模式都应用了工厂的概念,并可以使用在很多语言中。例如,在《设计模式》一书中,像工厂方法模式、抽象工厂模式、生成器模式,甚至是单例模式都应用了工厂的概念。 代码举例例如,有一个 //幾個Button類
class Button{/* ...*/}
class WinButton extends Button{/* ...*/}
class MacButton extends Button{/* ...*/}
//他們的工廠類別
interface ButtonFactory {
abstract Button createButton();
}
class WinButtonFactory implements ButtonFactory {
Button createButton() {
return new WinButton();
}
}
class MacButtonFactory implements ButtonFactory {
Button createButton() {
return new MacButton();
}
}
其他举例
变种虽然工厂方法模式的背后动机是允许子類別选择创建对象的具体類別,但是使用工厂方法模式也有一些其他的好处,其中很多并不依赖于子類別。因此,有时候也会创建不使用多态性创建对象的工厂方法,以得到使用工厂方法的其他好处。 工厂「方法」而非工厂「類別」如果抛开设计模式的范畴,“工厂方法”这个词也可以指作为“工厂”的方法,这个方法的主要目的就是创建对象,而这个方法不一定在单独的工厂類別中。这些方法通常作为静态方法,定义在方法所实例化的類別中。 每个工厂方法都有特定的名称。在许多面向对象的编程语言中,构造方法必须和它所在的類別具有相同的名称,这样的话,如果有多种创建对象的方式(重载)就可能导致歧义。工厂方法没有这种限制,所以可以具有描述性的名称。举例来说,根据两个实数创建一个复数,而这两个实数表示直角坐标或极坐标,如果使用工厂方法,方法的含义就非常清晰了。当工厂方法起到这种消除歧义的作用时,构造方法常常被设置为私有方法,从而强制客户端代码使用工厂方法创建对象。 下面的例子展示了在不同的编程语言中实现复数创建的代码: Javaclass Complex {
public static Complex fromCartesianFactory(double real, double imaginary) {
return new Complex(real, imaginary);
}
public static Complex fromPolarFactory(double modulus, double angle) {
return new Complex(modulus * cos(angle), modulus * sin(angle));
}
private Complex(double a, double b) {
//...
}
}
Complex product = Complex.fromPolarFactory(1, pi);
VB.NETPublic Class Complex
Public Shared Function fromCartesianFactory(real As Double, imaginary As Double) As Complex
Return (New Complex(real, imaginary))
End Function
Public Shared Function fromPolarFactory(modulus As Double, angle As Double) As Complex
Return (New Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle)))
End Function
Private Sub New(a As Double, b As Double)
'...
End Sub
End Class
Complex product = Complex.fromPolarFactory(1, pi);
C#public class Complex
{
public double Real;
public double Imaginary;
public static Complex FromCartesianFactory(double real, double imaginary)
{
return new Complex(real, imaginary);
}
public static Complex FromPolarFactory(double modulus, double angle)
{
return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle));
}
private Complex (double real, double imaginary)
{
Real = real;
Imaginary = imaginary;
}
}
var product = Complex.FromPolarFactory(1, pi);
简单工厂普通的工厂方法模式通常伴随着对象的具体類別与工厂具体類別的一一对应,客户端代码根据需要选择合适的具体類別工厂使用。然而,这种选择可能包含复杂的逻辑。这时,可以创建一个单一的工厂類別,用以包含这种选择逻辑,根据参数的不同选择实现不同的具体对象。这个工厂類別不需要由每个具体产品实现一个自己的具体的工厂類別,所以可以将工厂方法设置为静态方法。
而且,工厂方法封装了对象的创建过程。如果创建过程非常复杂(比如依赖于配置文件或用户输入),工厂方法就非常有用了。
比如,一个程序要读取图像文件。程序支持多种图像格式,每种格式都有一个对应的 public class ImageReaderFactory {
public static ImageReader imageReaderFactoryMethod(InputStream is) {
ImageReader product = null;
int imageType = determineImageType(is);
switch (imageType) {
case ImageReaderFactory.GIF:
product = new GifReader(is);
case ImageReaderFactory.JPEG:
product = new JpegReader(is);
//...
}
return product;
}
}
适用性工厂方法,适用于面向接口编程(programming to interface)与实现依赖反转原则。 下列情况可以考虑使用工厂方法模式:
工厂方法模式常见于工具包和框架中,在这些库中可能需要创建客户端代码实现的具体類別的对象。 平行的類別层次结构中,常常需要一个层次结构中的对象能够根据需要创建另一个层次结构中的对象。 工厂方法模式可以用于测试驱动开发,从而允许将類別放在测试中[2]。举例来说, 局限性使用工厂方法有三个局限,第一个与代码重构有关,另外两个与類別的扩展有关。
通过修改底层编程语言,使工厂方法称为第一類別的類別成员,可以缓解这三个问题。[3] 参考文献
参见 |