工厂类模式

浏览 544

课文

工厂方法模式(Factory Method Pattern)

情景

某家游戏店里售卖任天堂和索尼的产品,写成代码如下:

# 定义若干个商品类(Switch等),每调用一次create_good相当于返回一个商品
class Switch:
    def create_good(self):
        return "Switch游戏机"


class Zelda:
    def create_good(self):
        return "塞尔达"


class PS5:
    def create_good(self):
        return "PS5游戏机"


class TLOU:
    def create_good(self):
        return "最后生还者"

店里有一位叫小明的店员,他会询问顾客想要什么东西,并从货架上翻出来:

# 定义一个店员类,拥有一个搜索方法,并返回一个实例:
class Clerk:
    def search(self, goodsCls):
            return goodsCls()

今天小红来到店里,让小明给她拿一台 PS5,打算趁着假期玩一玩别人送的最后生还者:

xiaoming = Clerk()
ps5 = xiaoming.search(PS5)
print(ps5.create_good())

输出:

PS5游戏机

这就是最简单的工厂方法模式的流程。

正文

《设计模式》一书中,对工厂方法模式的描述是:定义一个用于创建对象的接口,让子类决定实例化哪一个类。怎么理解这段描述呢?

我们可以考虑将上面的例子套进去。例子中,店员类(Clerk)的search()方法即「创建对象的接口」,子类则是 Switch、PS5 等商品类,商品类中create_good()方法返回的字符串("PS5 游戏机"等)则作为「子类实例化的类」代替。

这时候聪明的同学要问了:我完全可以考虑跳过店员自己找到商品,为什么还要多此一举呢?

其实这是个设计模式的初学者都会有的疑问。因为在实际开发过程中,更多的情况不会像举例一样这么简单就能调用一个对象,而是:需要做一堆初始化工作、调取用户输入、获取一堆参数进行业务逻辑判断……等等,完成这些工作之后才能够创建并调用对象,但我们不希望这些东西暴露给客户端。就像平时买东西,只需要知道跟店员要这个东西,他就会拿出来,中间的生产、运输、仓储等等工作我们毫不关心。这就是工厂方法模式最大的意义,将创建对象的业务逻辑与调用剥离开,客户端只需要知道调用封装好的方法就能获取相应的对象,免去重写这部分代码的过程。

通常,我们将定义接口的类统称抽象工厂类,各个子类统称为具体工厂类,子类所实例化的类统称为产品类。

抽象工厂模式(Abstract Factory Pattern)

情景

将上述工厂方法模式的情景稍微做一下变更:游戏店里分为任天堂区和索尼区,每个区都卖游戏机和游戏:

class Switch:
    # __str__方法的返回值能够在print对象本身时,替代原本的打印值(即对象指向的内存地址
    def __str__(self):
        return "Switch游戏机"


    # 同样改写其他三个产品
    ···

class Nintendo:
    def create_console(self):
        return Switch()

    def create_game(self):
        return Zelda()


class SONY:
    def create_console(self):
        return PS5()

    def create_game(self):
        return TLOU()

同样提供小明,不过这次他只负责将你引导到专区:

class Clerk:
    def search(self, VendorCls):
            return VendorCls()

小花是一名认真刻苦的学生,之前从未接触过游戏,最近在微博上被人种草了 Switch 游戏机,但她不知道任天堂有什么游戏,她咨询了店员来到了任天堂专区,发现了塞尔达传说:

xiaoming = Clerk()
nintendo = xiaoming.search(Nintendo)
zelda = nintendo.create_game()
print(zelda)

输出:

塞尔达传说

这就是抽象工厂模式。

正文

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。同样套用上面的例子:

  • Switch 类和 Zelda 类就是定义中「相互依赖的对象」(属于同等厂商的不同产品),称为一个产品族,同理 PS5 类和 TLOU 类也是一个产品族;而 Switch 类与 PS5 类、Zelda 类与 TLOU 类属于不同厂商的同等产品,称为一个产品等级
  • Nintendo 类和 SONY 类则是定义中的「具体的类」,分别提供了create_console()方法和create_game()方法去返回对应产品族中同一产品等级结构的产品;
  • Clerk 类中的search()方法则是「接口」,它同样封装了一些业务逻辑,根据业务逻辑就能返回对应的具体的类。

实际上,抽象工厂模式与工厂方法模式非常相似,但其具体工厂类拥有多于一个返回实例的方法,而工厂方法模式只有一个。通常在项目开始时用工厂方法模式写了一套代码,之后随着项目的迭代,慢慢就会扩展成抽象工厂模式。

评论

登录参与讨论

暂无评论

共 0 条
  • 1
前往
  • 1