【编程学习】工厂模式-打造代码的优雅之道

工厂模式

常规的对象创建模式为直接用类来创建一个对象,但是这样创建对象和使用对象的职责耦合在一起,会出现耦合太强,导致后续会影响程序的拓展。

而当你的代码出现一下的一些情况,就十分适合运用工厂模式解决问题:

  • 两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有

  • 将对象的创建和使用分离,也使得系统更加符合“单一职责原则”,有利于对功能的复用和系统的维护

  • 防止用来实例化一个类的数据和代码在多个类中到处都是

  • 一些类实例的构建过程可能十分复杂,需要进行封装

  • 为类实例的构建提供更好的多态支持(不确定具体对象)

具体工厂模式的好处有以下几点:

  1. 模块间解耦、降低代码重复
  2. 减少使用者因为创建逻辑导致的错误。
  3. 一个调用者想创建一个对象,只要知道其名称就可以了。屏蔽产品的具体实现,调用者只关心产品的接口。
  4. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

但是也有一定的缺点:

  1. 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

实践

首先我们想要去构建一些水果类,有苹果、橘子等水果。首先,为了有一个优秀的代码编写风格,我们先构建一个抽象水果类Fruit(虽然没啥用)。

具体的AppleOrange,他们分别可以做苹果派和橘子汁:

1
2
3
4
5
6
7
8
9
10
class Fruit:
pass

class Apple(Fruit):
def pie(self):
print("making apple pie")

class Orange(Fruit):
def juice(self):
print("making orange juice")

简单工厂

我们可以之间简单创建一个水果工厂FruitFactory,在工厂中我们根据用户传入的参数选择合适的水果进行实例化。

1
2
3
4
5
6
7
8
class FruitFactory:
def generate_fruit(self,type):
if type=='a':
return Apple()
elif type=='o':
return Orange()
else:
return None

但是这种简单工厂模式有很多问题,比如如果用户需要新添加一个水果,就需要深入源代码,修改FruitFactory类,这违背了“开闭原则”。

抽象工厂

用抽象工厂的方法可以很好解决简单工厂的缺点,首先我们要构建一个抽象的工厂,然后再进一步构建生成苹果和橘子的工厂:

1
2
3
4
5
6
7
8
9
10
11
class Factory:
def generate(self):
pass

class AppleFactory(Factory):
def generate(self):
return Apple()

class OrangeFactory(Factory):
def generate(self):
return Orange()

具体运行看一下结果:

1
2
3
4
5
6
7
8
9
10
11
af = AppleFactory()
apple = af.generate()
apple.pie()

of = OrangeFactory()
orange = of.generate()
orange.juice()

# output:
# making apple pie
# making orange juice

如果我们想再加一个水果,比如是香蕉,可以用橡胶来做香蕉奶昔:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Banana(Fruit):
def milkshake(self):
print("making banana milkshake")

class BananaFactory(Factory):
def generate(self):
return Banana()

bf = BananaFactory()
banana = of.generate()
banana.milkshake()

# output:
# making banana milkshake

此时,我们不需要修改其他类的代码与调用方法,只需要新添加需要的类和属性即可。极大的增加了代码的可拓展性。

当然,由于我们每增加一个新的产品时就要增加一个新的具体产品类和一个对应的具体工厂类,这大大增加了系统的复杂度。