文章

设计模式-工厂方法模式

Defer the creation of an object to sub classes.

推迟子类中某个对象的创建时间.

这是在设计模式中对工厂方法模式的定位说明.

简单来说, 工厂方法的用法是定义一个接口, 其实现提供某些基类需要的功能. 基类通过工厂方法获得这一接口的实例, 而子类则可以重写该方法以选择其他的实例.

举一个汽车的例子. 奔驰有自己的原厂车, 但是子品牌AMG就提供性能更强的版本.

classDiagram
    direction LR
    class Engine{
        <<interface>>
        + powerOutput()
    }
    class Benz{
        <<interface>>
        + speedup()
        + useEngine()->Engine
    }
    class BenzE300L{
        + speedup()
        + useEngine()
    }
    class BenzAMGE53{
        + speedup()
        + useEngine()
    }
    class L420TEngine{
        + powerOutput()
    }
    class L630TEngine{
        + powerOutput()
    }

    Benz *--> Engine
    Benz <|-- BenzE300L
    Benz <|-- BenzAMGE53

    Engine <|-- L420TEngine
    Engine <|-- L630TEngine

    BenzE300L *--> L420TEngine
    BenzAMGE53 *--> L630TEngine

简单的python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from abc import ABC, abstractmethod


class Engine(ABC):

    @abstractmethod
    def power_output(self):
        pass


class L420TEngine(Engine):

    def power_output(self):
        return 258


class L630TEngine(Engine):

    def power_output(self):
        return 435


class Benz(ABC):

    def speed_up(self):
        horsepower = self._use_engine().power_output()
        t = 100/(10.6+(horsepower-258)*12.2/177)
        print(f'With {horsepower}hp, 0-100km need {round(t, 2)} seconds.')

    @abstractmethod
    def _use_engine(self):
        pass


class BenzE300L(Benz):

    def _use_engine(self):
        return L420TEngine()


class BenzAMGE53(Benz):

    def _use_engine(self):
        return L630TEngine()


if __name__ == "__main__":

    e300 = BenzE300L()
    e300.speed_up()
    amg = BenzAMGE53()
    amg.speed_up()

Benz作为一个抽象类, 实现了大部分的逻辑, 同时把变量部分抽象为接口, 也就是示例中的Engine.

_use_engine则扮演了工厂方法角色, 通过该方法返回一个参与业务逻辑所需要的对象.

由于这个对象是Engine的实现类, 只需要扩展其他的实现就可以使业务逻辑得到不同的结果.

两个具体车型的子类则是继承自Benz抽象类, 重写其工厂方法, 返回其他的实例, 便完成了新的扩展.

很多对工厂方法的示例是通过一个工厂对象的静态方法返回一个对象.

那就是用错了…

只要工厂在扩展, 工厂类就需要一直维护, 变的越来越臃肿.

而调用工厂的特定方法也是需要硬编码, 最终变成两边维护.

工厂方法是通过继承和重写来快速实现对不同组合的扩展

本文由作者按照 CC BY 4.0 进行授权