Python之工厂模式
一、介绍
工厂模式(Factory Pattern)是最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
何时使用:我们明确地计划不同条件下创建不同实例时。
二、简单工厂
统一使用一个类作为对外接口,根据参数的不同,去选择实例化不同的类。
""" 两个产品(两种类型的书) """ class TechnicalBooks(object): """技术书籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """文学书籍""" def publish(self): return "Black Hole Book" # 现在我们有两种类型的书,分别是TechnicalBooks和LiteraryBooks的书 # 按照我们平常的方法来实例化的话,此时创建对象时是会对客户端暴露真正创建的类 it_books = TechnicalBooks() ly_books = LiteraryBooks() # 这时我们就可以构造一个"简单工厂"把所有实例化的过程封装在里面,把真正实例的类隐藏起来 class SimpleFactory(object): """简单工厂""" @staticmethod def publish_book(name): if name == 'technical': return TechnicalBooks() elif name == 'literary': return LiteraryBooks() it_books2 = SimpleFactory.publish_book('technical') ly_books2 = SimpleFactory.publish_book('literary')
简单工厂的好处在于,把不同类的实例化统一到一个"工厂",即不对外暴露真正的创建类,也提供了一个对外的统一接口。
但是简单工厂也有一个缺点,那就是违背了solid的 "开闭原则",假如我们还需要增加一种书籍,那就必须要对简单工厂SimpleFactory进行源码的修改,
简单工厂使用场景:
- 已经确定有多少具体的类,不会再增加的情况下使用。
例如:某个系统,已经明确就只会有MySQL、Redis、MongoDB三个数据库的情况下,可以直接使用简单工厂模式。
三、工厂方法
上面的简单工厂我们已经知道了,如果新增一些类型的时候会违背软件设计中的开闭原则,但是我们希望在扩展新的类时,不要修改原有的代码。这个时候我们可以在简单工厂的基础上把SimpleFactory抽象成不同的工厂,每个工厂对应生成自己的产品,这就是工厂方法。
""" 两个产品(两种类型的书) """ import abc # 真正进行实例化的类 class TechnicalBooks(object): """技术书籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """文学书籍""" def publish(self): return "Black Hole Book" # 抽象工厂:先定义抽象类,然后每种类型的书籍都有自己对于的工厂 class AbstractFactory(metaclass=abc.ABCMeta): """抽象工厂""" @abc.abstractmethod def publish_book(self): pass class TechnicalFactory(AbstractFactory): """技术书籍工厂""" def publish_book(self): return TechnicalBooks() class LiteraryFactory(AbstractFactory): """文学书籍工厂""" def publish_book(self): return LiteraryBooks() it_books2 = TechnicalFactory().publish_book() ly_books2 = LiteraryFactory().publish_book()
这样每个工厂就只负责生产自己的产品,避免了在新增产品时需要修改工厂的代码,遵循了"开闭原则",如果需要新增产品时,只需要增加相应的工厂即可。
比如要新增一种小说类型的书籍,只需新增一个NovelBooks类和NovelFactory类。
工厂方法的使用场景:
- 当系统中拥有的子类很多,并且以后可能还需要不断拓展增加不同的子类时。
- 当设计系统时,还不能明确具体有哪些类时。
在工厂方法中,使用者不需要知道具体的产品类名,只需要知道其对应的工厂即可。
四、抽象工厂
工厂方法解决了"开闭原则"的问题,但是我们出版书籍之前肯定还会有其他的步骤,比如印刷。
如果每一个步骤我们就要写一个对应的工厂类,那我们就会需要创建很多很多类了。
因此为了解决这个问题,我们就要需要抽象工厂类,让一个工厂可以生产同一类的多个产品或多个动作(步骤),这就是抽象工厂。
""" 两个产品(两种类型的书) """ import abc # 印刷书籍 class PrintingTechnicalBooks(object): """印刷技术书籍""" def printing(self): return "Print-Python-Book" class PrintingLiteraryBooks(object): """印刷文学书籍""" def printing(self): return "Print Black Hole Book" # 出版书籍 class TechnicalBooks(object): """出版技术书籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """出版文学书籍""" def publish(self): return "Black Hole Book" # 抽象工厂:先定义抽象类,然后每种类型的书籍都有自己对于的工厂 class AbstractFactory(metaclass=abc.ABCMeta): """抽象工厂""" @abc.abstractmethod def print_book(self): pass @abc.abstractmethod def publish_book(self): pass class TechnicalFactory(AbstractFactory): """技术书籍工厂""" def print_book(self): return PrintingTechnicalBooks() def publish_book(self): return TechnicalBooks() class LiteraryFactory(AbstractFactory): """文学书籍工厂""" def print_book(self): return PrintingLiteraryBooks() def publish_book(self): return LiteraryBooks() # 实例化工厂对象 it = TechnicalFactory() ly = LiteraryFactory() # 印刷书籍 it_print = it.print_book() ly_print = ly.print_book() # 出版书籍 it_publish = it.publish_book() ly_publish = ly.publish_book()
抽象工厂模式与工厂方法模式的区别:
抽象工厂中的一个工厂对象可以负责多个不同产品对象的创建
抽象工厂的使用场景:
- 当多个产品(步骤)集合在一起,组成产品族时。
- 对于一个产品族,如果只想显示接口而不是实现时。