1 模式的定义
工厂方法模式是一种常见的设计模式,属于创建型设计模式之一,它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化,将具体对象的实例化延迟到子类中完成,以便在不同情况下可以创建不同类型的对象,而客户端代码不需要知道实际创建的对象类型。
2 举例说明
不同公司都生产自己的手机,就符合工厂方法模式。比如小米和华为都是手机制造商,而手机则是产品。每家公司都有自己的生产流程和标准,但它们都需要生产手机以满足市场需求。
工厂方法模式中,每家公司都有一个具体的工厂(小米工厂和华为工厂),这些工厂实现了一个共同的抽象工厂接口。抽象工厂定义了一个方法用于生产手机,但具体的手机生产过程由每家公司的工厂来实现。
客户端代码可以根据需要选择使用小米工厂或华为工厂来生产手机。这种方式下,客户端代码无需关心手机的具体制造过程,只需知道如何与抽象工厂交互即可。
工厂方法模式的优点在于它实现了对象的创建和客户端代码的解耦,使得不同的工厂可以独立扩展,适用于多样化的产品生产场景。小米和华为手机的制造就是一个生动的示例,其中工厂方法模式为不同公司的手机生产提供了一种灵活的、可扩展的解决方案
3 结构
工厂方法模式的结构包括以下几个关键角色:
- 抽象工厂接口(Factory):这是工厂方法模式的核心部分,它定义了一个或多个工厂方法的接口,这些方法用于创建具体产品对象。通常,这个接口中会包含多个方法,每个方法用于创建不同类型的产品。客户端代码通过调用这些工厂方法来获取产品对象。
- 具体工厂类(Concrete Factory):这是实现抽象工厂接口的具体类,每个具体工厂类负责创建一类具体产品。它实现了工厂方法,根据客户端的需求创建具体的产品对象。每个具体工厂类通常对应一个特定的产品族。
- 抽象产品接口(Product):这个接口定义了产品对象的通用属性和方法,所有具体产品类都必须实现这个接口。客户端代码将与抽象产品接口进行交互,而不直接与具体产品类进行交互。
- 具体产品类(Concrete Product):这些是实际的产品类,它们实现了抽象产品接口,定义了具体产品的属性和行为。每个具体产品类对应一个具体工厂类。
- 客户端(Client):客户端代码需要创建产品对象,但它不直接与具体产品类或具体工厂类交互。客户端通过调用抽象工厂接口中的工厂方法来创建产品对象,从而实现了解耦的目的。
工厂方法模式的结构允许在不修改客户端代码的情况下引入新的具体产品类和具体工厂类,从而增加系统的可扩展性。客户端只需要知道抽象工厂接口和抽象产品接口,而不需要关心具体的产品类和工厂类,这使得系统更易于维护和扩展。
总结来说,工厂方法模式的结构包括抽象工厂接口、具体工厂类、抽象产品接口、具体产品类以及客户端。这个模式通过将对象的创建委托给具体工厂类来实现对象的创建和客户端与产品之间的解耦。
4 实现步骤
工厂方法模式的实现步骤通常包括以下几个关键步骤:
- 定义抽象产品接口(Product):定义一个抽象产品接口,它声明了产品对象的通用属性和方法。所有具体产品类都必须实现这个接口。
- 创建具体产品类(Concrete Product):实现抽象产品接口的具体产品类。每个具体产品类表示一种具体的产品。
- 定义抽象工厂接口(Factory):创建一个抽象工厂接口,该接口声明了工厂方法,用于创建产品对象。
- 创建具体工厂类(Concrete Factory):实现抽象工厂接口的具体工厂类,每个具体工厂类负责创建特定类型的产品。在客户端中使用工厂方法:
- 客户端代码通过具体工厂类的工厂方法来创建产品对象,而不直接实例化具体产品类。
通过上述步骤,您就可以实现工厂方法模式。这种模式允许客户端根据需要选择合适的具体工厂来创建产品,从而实现了解耦和可扩展性。如果需要添加新的产品类型,只需创建新的具体产品类和对应的具体工厂类,而不需要修改现有的客户端代码。
5 代码实现
以下是使用工厂方法模式实现抽象工厂(AbstractFactory
)、具体工厂(XiaomiFactory
、HuaweiFactory
)、抽象产品(AbstractMobile
)和具体产品(XiaomiMobile
、HuaweiMobile
)的Java代码示例:
// 抽象产品接口
interface AbstractMobile {
void displayInfo();
}
// 具体产品类 - 小米手机
class XiaomiMobile implements AbstractMobile {
@Override
public void displayInfo() {
System.out.println("这是小米手机。");
}
}
// 具体产品类 - 华为手机
class HuaweiMobile implements AbstractMobile {
@Override
public void displayInfo() {
System.out.println("这是华为手机。");
}
}
// 抽象工厂接口
interface AbstractFactory {
AbstractMobile createMobile();
}
// 具体工厂类 - 小米工厂
class XiaomiFactory implements AbstractFactory {
@Override
public AbstractMobile createMobile() {
return new XiaomiMobile();
}
}
// 具体工厂类 - 华为工厂
class HuaweiFactory implements AbstractFactory {
@Override
public AbstractMobile createMobile() {
return new HuaweiMobile();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
// 使用具体工厂创建具体产品
AbstractFactory xiaomiFactory = new XiaomiFactory();
AbstractMobile xiaomiMobile = xiaomiFactory.createMobile();
xiaomiMobile.displayInfo();
AbstractFactory huaweiFactory = new HuaweiFactory();
AbstractMobile huaweiMobile = huaweiFactory.createMobile();
huaweiMobile.displayInfo();
}
}
在这个代码示例中,我们定义了抽象产品接口 AbstractMobile
和两个具体产品类 XiaomiMobile
和 HuaweiMobile
。然后,我们定义了抽象工厂接口 AbstractFactory
,其中包含了一个工厂方法 createMobile()
,用于创建手机产品。
接下来,我们创建了两个具体工厂类 XiaomiFactory
和 HuaweiFactory
,分别实现了 AbstractFactory
接口,并在其中实现了工厂方法,分别用于创建小米手机和华为手机。
最后,在客户端代码中,我们使用不同的具体工厂来创建不同的手机产品,从而实现了工厂方法模式,客户端代码不需要知道具体产品的细节,只需要知道如何使用抽象工厂来创建产品
6 典型应用场景
6.1 数据库驱动程序的创建
使用工厂方法模式来进行数据库驱动程序创建的场景是在软件开发中需要连接不同类型的数据库(例如MySQL、PostgreSQL、Oracle等)时。通过工厂方法模式,可以将不同数据库的连接对象的创建过程封装在各自的工厂类中,客户端代码无需关心具体的数据库驱动程序实现,只需使用相应的工厂来创建数据库连接对象,从而实现了灵活性和可扩展性,能够轻松地切换和添加新的数据库驱动程序,而不影响现有的代码。这种模式在多数据库支持和数据库连接的抽象化方面非常有用。
6.1 UI控件的创建
使用工厂方法模式进行UI控件创建的场景是在图形用户界面(GUI)开发中。不同操作系统或界面库(如Windows、macOS、Android等)可能使用不同的UI控件(如按钮)。通过工厂方法模式,可以将每种UI控件的创建过程封装在各自的工厂类中,客户端代码无需关心具体的控件实现,只需使用相应的工厂来创建控件对象,从而实现了跨平台和可扩展性,使得应用程序能够在不同的操作系统或界面库下创建合适的UI控件,而不需要重写整个界面代码。这种模式在多平台UI开发和UI组件的抽象化方面非常有用。
6.3 日志记录器
在应用程序中需要记录日志以进行调试、故障排除和性能监测时。不同的日志记录方式(如文件日志、数据库日志、控制台日志等)可能需要使用不同的日志记录器。通过工厂方法模式,可以将每种日志记录器的创建过程封装在各自的工厂类中,客户端代码无需关心具体的日志记录器实现,只需使用相应的工厂来创建日志记录器对象,从而实现了灵活性和可扩展性,使得应用程序可以根据需求选择不同的日志记录方式,而不需要修改主要的应用逻辑。这种模式在日志记录方式的切换和定制化日志记录方面非常有用。
6.4 游戏中不同角色的创建
使用工厂方法模式来创建游戏中不同角色的场景是在游戏开发中。在游戏中,有各种不同类型的角色(如玩家、敌人、道具、NPC等),每个角色都有自己独特的属性和行为。通过工厂方法模式,可以将每种角色的创建过程封装在各自的工厂类中,客户端代码无需关心具体的角色实现,只需使用相应的工厂来创建角色对象,从而实现了游戏角色的动态创建和管理。这种模式在游戏中角色的扩展和多样化方面非常有用,使得游戏开发人员可以轻松地添加新的角色类型,而不需要修改游戏引擎或核心逻辑。
7 优缺点
工厂方法模式是一种常用的设计模式,它具有一些优点和缺点:
优点:
松耦合 :工厂方法模式将对象的创建过程封装在工厂类中,客户端代码与具体产品类解耦。客户端代码只需要关心抽象工厂和产品接口,无需了解具体产品的细节。
可扩展性 :通过添加新的具体工厂类和具体产品类,可以轻松扩展系统以支持新的产品类型,而不需要修改现有的代码。这使得系统更容易维护和扩展。
多态性 :工厂方法模式利用了多态性,使得客户端可以根据需要创建不同类型的产品对象,而无需改变客户端代码。
符合开闭原则 :工厂方法模式遵循开闭原则,对修改关闭,对扩展开放。添加新的产品类型只需要添加新的具体工厂类和具体产品类,而不需要修改现有代码。
缺点:
类的数量增加 :引入工厂方法模式会增加类的数量,每个具体产品类都需要一个对应的具体工厂类。对于一些简单的情况,可能会使代码变得复杂。
复杂性增加 :在有多层继承结构的情况下,可能会引入更多的层次,增加代码的复杂性。
不适用于单例 :工厂方法模式通常用于创建多个对象,不适用于创建单例对象。对于单例模式,通常使用其他模式,如单例模式或者静态工厂方法。
增加代码复杂度 :在简单情况下,使用工厂方法模式可能会增加不必要的复杂性,不如直接实例化对象来得简单。
总之,工厂方法模式在实现对象的创建和客户端代码解耦方面有很多优点,但也需要谨慎使用,根据具体情况来决定是否使用该模式,以确保代码的可维护性和扩展性。
8 类似模式
工厂方法模式、抽象工厂模式和简单工厂模式都是创建型设计模式,用于对象的创建,但它们在关注点和应用场景上存在差异。
简单工厂模式是一种简化对象创建的方法,不是 GoF(Gang of Four)的正式设计模式。简单工厂适用于创建少量的对象,但不符合开闭原则,不支持扩展新的产品类型。
工厂方法模式是一种正式的设计模式,定义了一个创建对象的接口,具体的对象创建延迟到子类中完成。用于创建单一产品等级结构。
抽象工厂模式也是一种正式的设计模式,提供一个接口,用于创建一系列相关或依赖的对象,不需要指定具体的类。每个具体工厂类可以创建一组相关的产品,用于创建多个相关的产品等级结构或整个产品族。
它们都以不同的方式提供了对象创建的灵活性和可扩展性,根据需求选择合适的模式。
9 小结
工厂方法模式是一种常用的设计模式,属于创建型设计模式,其核心思想是将对象的创建延迟到子类中去完成。特别适合在需要创建多个相关但不同类型的对象时,以提高代码的可维护性和可扩展性。它将对象的创建过程进行了抽象,使得客户端代码更加灵活,可以根据需要选择不同的具体工厂来创建对象。