工厂方法(Factory):定义创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。

说人话:工厂方法模式将之前负责生成具体抽象子类的工厂类,抽象为工厂抽象类和工厂子类组成的一系列类。每创建一个抽象子类,就需要创建一个工厂子类,并且一一对应,由工厂子类去生成对应的抽象子类,由外界使用方来决定生成哪个工厂子类。这样在增加新的需求时,就不需要对工厂抽象类进行修改,而是对应新增的抽象子类创建对应的工厂子类即可。

主要参与者

  • 抽象工厂角色:与应用程序无关,任何在模式中创建对象的工厂必须实现这个接口。
  • 具体工厂角色:实现了抽象工厂接口的具体类,含有与引用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
  • 抽象产品角色:工厂方法所创建产品对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品角色:这个角色实现了抽象产品角色所声名的接口。工厂方法所创建的每个具体产品对象都是某个具体产品角色的实例。

类图

工厂方法

我们讲过,既然这个工厂类与分支耦合,那么我就对它下手,根据依赖倒转原则,我们把工厂类抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后,所有的要生产具体类的工厂,就去实现这个接口,这样,一个简单工厂模式的工厂类,变成一个工厂抽象接口和多个具体生成对象的工厂,于是我们要增加‘求M数的N次方’的功能时,就不需要更改原有的工厂类了,只需要增加此功能的运算类和相应的工厂类就可以了

使用场景

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
  • 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
  • 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

实现

抽象工厂类

1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
#import "ILeiFeng.h"
@protocol ILeiFengFactory <NSObject>
- (id<ILeiFeng>)createLeiFeng;
@end

具体工厂类

UndergraduateFactory
  • objectivec
  • objectivec
1
2
3
4
5
6
#import <Foundation/Foundation.h>
#import "ILeiFengFactory.h"

@interface UndergraduateFactory : NSObject<ILeiFengFactory>

@end

抽象产品类

1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>
@protocol ILeiFeng <NSObject>
// 扫地
- (void)sweep;
// 洗衣
- (void)wash;
// 买米
- (void)buyRice;
@end

具体产品类

Undergraduate
  • objectivec
  • objectivec
1
2
3
4
5
6
#import <Foundation/Foundation.h>
#import "ILeiFeng.h"

@interface Undergraduate : NSObject<ILeiFeng>

@end

测试用例

1
2
3
4
5
6
7
8
9
实现
- (void)testFactoryMethod {
//id<ILeiFengFactory> iLeiFengFactory = [[UndergraduateFactory alloc] init];
id<ILeiFengFactory> iLeiFengFactory = [[VolunteerFactory alloc] init];
id<ILeiFeng> iLeiFeng = [iLeiFengFactory createLeiFeng];
[iLeiFeng sweep];
[iLeiFeng wash];
[iLeiFeng buyRice];
}

优点

工厂方法模式的的优点在于更大的灵活性,增加或删除某个产品都不会对其他地方造成影响,更佳符合开放封闭原则。
而且对抽象的使用更佳深入,将工厂类也抽象为了抽象工厂类和工厂子类,外界调用更加灵活,这也是对多态的一种体现。

缺点

工厂方法模式的缺点也是非常显而易见的,工厂方法模式中新增一个抽象子类,意味着工厂子类要跟着成对增加(OC中要x4😭),这样会造成生成过多的类,工厂方法模式的复杂度也会随之增加。

应用场景

在了解了优缺点后,我总结了工厂方法模式的应用场景:

  • 当一个类不知道它所需要的对象的类时
    在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
  • 当一个类希望通过其子类来指定创建对象时
    在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展;
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。