【设计模式】工厂方法模式(Factory Method)
上一节我们学了类间关系以及UML类图,现在我们来看看工厂方法模式。
工厂
在面向对象程序设计中,工厂是一个用来创建其他对象的对象。它提供了一种抽象的构造方法,用于实现不同的对象创建方案。工厂对象通常包含一个或多个方法,这些方法用于创建工厂所能生成的不同类别的对象。这些方法可能会接收参数,以指定对象创建的方式,并最终返回创建的对象。
当对象的创建涉及到复杂的控制过程、配置或其他操作时,工厂对象可以负责将这些细节封装起来,使客户端代码保持简洁,专注于业务逻辑。
不同的设计模式,如工厂方法模式、抽象工厂模式、生成器模式、单例模式等,都应用了工厂的概念。这些模式通过不同的方式组织和实现工厂,以满足不同的设计需求,提高代码的可维护性和可复用性。
工厂方法模式
工厂方法模式(Factory method pattern)是一种实现了 “工厂” 概念的面向对象设计模式,属于创建型模式。工厂方法模式用于处理在不指定对象具体类别的情况下创建对象的问题。
模式意图:定义一个创建对象的接口,但让实现这个接口的具体类来决定实例化哪些类。工厂方法让类的实例化推迟到子类中进行。
类图 | 结构与角色分析
先看类图:
下面是角色分析。
Product
Product
(产品):抽象类,定义了工厂方法模式中生成的那些实例所持有的属性和方法,但具体的处理则由子类ConcreteProduct
角色来决定。
1 | /** |
Creator
Creator
(创建者):声明工厂方法factoryMethod
,负责生成Product
。但具体的处理则由子类ConcreteCreator
角色来决定。注意!Creator
对于实际负责生成实例的ConcreteCreator
角色一无所知,它唯一知道的就是可以调用Product
角色,生成Product
实例对象。
1 | /** |
注意,这里将 factoryMethod
方法定义为抽象方法,因此子类必须实现这个方法来创建真正的实例。
ConcreteProduct
ConcreteProduct
(具体的产品):具体产品角色。
1 | /** |
ConcreteCreator
ConcreteCreator
(具体的创建者):属于具体加工这一方,负责生成具体的产品,返回一个具体的Product
对象。
1 | public class ConcreteCreator extends Creator { |
举例 | 电视机工厂生产电视机的例子
类图
客户端使用
我们首先来看客户端的使用效果:
1 | // 客户端代码,使用工厂创建产品并调用其方法 |
运行效果:
1 | (1)海尔工厂正在生产海尔电视机... |
产品角色(Product)
TV
表示工厂方法模式中的抽象产品“电视机”,由抽象类来实现(也可以定义为接口)。
1 | abstract class TV { //角色1:Product |
工厂角色(Creator)
Factory
是一个抽象类,声明创建产品对象的抽象方法createProduct
,具体处理让子类去实现。
1 | abstract class Factory { //角色2:Creator |
具体产品角色(ConcreteProduct)
HaierTV
是产品角色TV
的实现类,是工厂方法创建的实际对象。
1 | class HaierTV extends TV { //角色3:ConcreteProduct |
具体工厂角色(ConcreteCreator)
HaierFactory
是工厂角色Factory
的具体实现类,实现了创建产品的方法createProduct
,生成具体的产品对象HaierTV
。
1 | class HaierFactory extends Factory { //角色4:ConcreteCreator |
模式优点
工厂方法模式通过将产品的实例化延迟到具体的工厂类,实现了客户端与具体产品的解耦。
1 | class HaierFactory extends Factory { |
客户端通过调用具体工厂的createProduct
方法来获取产品实例,而无需关心具体产品的创建过程。
新增产品时,只需新增一个具体工厂类继承自抽象工厂,重写抽象工厂中的抽象方法,这样可以在不修改已有具体工厂类的情况下引进新的产品,符合开闭原则,降低了耦合度。
开闭原则:对修改封闭,对扩展开放。
新增产品
比如现在,我们引入新的产品:索尼电视机。
1 | class SonyTV extends TV { //角色:ConcreteProduct |
以及具体的工厂类:
1 | class SonyFactory extends Factory { //角色:ConcreteCreator |
现在,我们来客户端中测试一把:
1 | public class Client{ //客户端 |
运行效果:
1 | (1)海尔工厂正在生产海尔电视机... |
类图如下:
总结
“在工厂方法模式中,父类决定实例的生成方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责。将生成实例的框架(framework)和实际负责生成实例的类进行解耦”。
我们总结一下,对于工厂方法模式来说,它就是封装一个创建对象的抽象类(或者说接口),由该抽象类的子类来决定实例化哪一个产品类,因此我们说工厂方法模式将类的实例化延迟到子类中完成。产品类可以有很多个,作为客户端(调用者)来说,只需调用工厂方法返回产品即可(我要什么你就给我什么)。