目录
更多关于Python的相关技术点,敬请关注公众号:CTO Plus后续的发文,有问题欢迎后台留言交流。
工厂方法(Factory Method)模式是一种常见的创建型设计模式,它通过定义一个创建对象的接口,但是它将对象的创建延迟到子类中实现,每个具体子类都可以创建自己特定的对象。工厂方法模式将对象的创建和使用分离开来,客户端只需要知道工厂类和产品的接口,而不需要知道具体的产品实现。工厂方法是一个方法,同比Python中的一个函数,对不同的输入参数返回不同的对象。
原文:Python设计模式之创建型-工厂方法模式(Factory Method)
在本文中,我们将介绍工厂方法模式的概念、作用、特点和使用方法,以及使用4个Python代码示例分别实现工厂方法模式,包括通过创建不同类型的动物、解析不同类型的文本文件来演示该模式的应用。
在前面的文章《关于Python设计模式的一些事情,设计模式是否真能帮你解决什么问题?》中对Python的设计模式进行了一个大体的分享介绍。
【Python设计模式系列】
-
《Python设计模式之创建型-简单工厂模式(Simple Factory)》
-
《Python设计模式之创建型-工厂方法模式(Factory Method)》
-
《Python设计模式之创建型-抽象工厂模式(Abstract Factory)》
-
《Python设计模式之创建型-创建者(建造者)模式(Builder)》
-
《Python设计模式之创建型-原型模式(Prototype)》
-
《Python设计模式之创建型-对象池模式(Pool)》
-
《Python设计模式之创建型-惰性评价模式(Lazy Evaluation)》
-
《Python设计模式之结构型-代理模式(Proxy)》
-
《Python设计模式之结构型-适配器模式(Adapter)》
-
《Python设计模式之结构型-装饰器模式(Decorator)》
-
《Python设计模式之结构型-组合模式(Composite)》
-
《Python设计模式之结构型-外观模式(Facade)》
-
《Python设计模式之结构型-享元模式(Flyweight)》
-
《Python设计模式之结构型-桥接模式(Bridge)》
-
《Python设计模式之结构型-3层模式(3-tier)》
-
《Python设计模式之结构型-前端控制器模式(front controller)》
-
《Python设计模式之结构型-MVC模式(mvc)》
-
《Python设计模式之行为型-观察者模式(Observer)》
-
《Python设计模式之行为型-模板方法(Template Method)模式》
-
《Python设计模式之行为型-策略模式(Strategy)》
-
《Python设计模式之行为型-职责链模式(Chain of Responsibility)》
-
《Python设计模式之行为型-状态模式(State)》
-
《Python设计模式之行为型-迭代器模式(Iterator)》
-
《Python设计模式之行为型-访问者(访客)模式(Visitor)》
-
《Python设计模式之行为型-命令模式(Command)》
-
《Python设计模式之行为型-解释器模式(Interpreter)》
-
《Python设计模式之行为型-调停者(中介者)模式(Mediator)》
-
《Python设计模式之行为型-备忘录模式(Memento)》
-
《Python设计模式之行为型-目录模式(catalog)》
-
《Python设计模式之行为型-方法链模式(chaining method)》
-
《Python设计模式之行为型-发布订阅模式(publish subscribe)》
-
《Python设计模式之行为型-注册模式(registry)》
-
《Python设计模式之行为型-规格模式(specification)》
在前面的文章中对简单工厂做了详细介绍,工厂方法和简单工厂的区别在于,简单工厂模式只有一个工厂,工厂方法模式对每一个产品都有相应的工厂。工厂方法模式是简单工厂模式的一个衍生扩展,解决了许多简单工厂模式存在的问题。首先完全实现“开-闭原则”,实现了可扩展,其次是更复杂的层次结构,可以应用于产品结果复杂的场合。
工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Templete Method pattern)应用。关于模板方法模式的详细介绍请关注公众号CTO Plus后面的文章《Python设计模式之行为型-模板方法(Template Method)模式》
作用
定义一个用于创建对象的接口,但是由子类决定要实例化的类是哪一个。Factory Method 使一个类的实例化延迟到其子类。
适用场景
工厂方法的适用场景包括:
1. 当一个类无法预知要创建的对象的类时,可以使用工厂方法模式来将对象的创建延迟到子类中,从而实现解耦。
2. 当需要在运行时动态地决定要创建的对象的类时,可以使用工厂方法模式来根据条件选择不同的子类来创建对象。
3. 当需要通过继承来扩展对象的创建时,可以使用工厂方法模式来定义一个创建对象的接口,并在子类中实现具体的对象创建逻辑。
优缺点
工厂方法模式的优点
1. 将对象的创建和使用解耦,客户端只需要关心对象的使用,而不需要关心对象的创建细节。
2. 可以通过继承来扩展对象的创建,符合开闭原则,对修改关闭,对扩展开放。
3. 可以通过配置文件或者反射等方式来动态地决定要创建的对象的类。
4. 增加一个运算类(例如N次方类),只需要增加运算类和相对应的工厂两个类,不需要修改工厂类。
工厂方法模式的缺点
1. 增加了系统的复杂度和理解难度,需要理解和掌握工厂方法模式的概念和使用方法。
2. 增加了代码的数量和复杂度,需要定义和实现多个工厂类和产品类。
3. 增加运算类,会修改客户端代码,工厂方法只是把简单工厂的内部逻辑判断移到了客户端进行
问题描述
假设我们正在开发一个动物园管理系统,我们需要能够创建不同类型的动物,如狗、猫和鸟等。每种动物都有自己的特点和行为,我们希望能够通过一个工厂方法来创建这些动物对象。
实现步骤
首先,我们需要定义一个抽象的动物类Animal,其中包含一个抽象方法make_sound,用于发出动物的叫声。然后,我们创建具体的动物子类,如Dog、Cat和Bird,分别实现make_sound方法,分别表示狗、猫和鸟的叫声。
接下来,我们定义一个抽象的动物工厂类AnimalFactory,其中包含一个抽象方法create_animal,用于创建具体的动物对象。然后,我们创建具体的动物工厂子类,如DogFactory、CatFactory和BirdFactory,分别实现create_animal方法,分别用于创建狗、猫和鸟的对象。
最后,我们在客户端代码中使用动物工厂来创建不同类型的动物对象,并调用其make_sound方法来发出叫声。
代码示例1
import settings
# 定义抽象的动物类
class Animal:
def make_sound(self):
pass
# 定义具体的动物子类
class Dog(Animal):
def make_sound(self):
print(f"DOG:{settings.BLOG}")
class Cat(Animal):
def make_sound(self):
print(f"CAT:{settings.优快云}")
class Bird(Animal):
def make_sound(self):
print(f"BIRD:{settings.GIT}")
# 定义抽象的动物工厂类
class AnimalFactory:
def create_animal(self):
print()
# 定义具体的动物工厂子类
class DogFactory(AnimalFactory):
def create_animal(self):
return Dog()
class CatFactory(AnimalFactory):
def create_animal(self):
return Cat()
class BirdFactory(AnimalFactory):
def create_animal(self):
return Bird()
# 客户端代码
if __name__ == '__main__':
# 创建狗对象
dog_factory = DogFactory()
dog = dog_factory.create_animal()
dog.make_sound()
# 创建猫对象
cat_factory = CatFactory()
cat = cat_factory.create_animal()
cat.make_sound()
# 创建鸟对象
bird_factory = BirdFactory()
bird = bird_factory.create_animal()
bird.make_sound()
代码示例2
下面是一个工厂方法模式的示例代码:
import settings
from abc import ABC, abstractmethod
class Product(ABC):
@abstractmethod
def do_something(self):
pass
class ConcreteProductA(Product):
def do_something(self):
print(f"view {settings.BLOG}")
class ConcreteProductB(Product):
def do_something(self):
print(f"view {settings.优快云}")
class Factory(ABC):
@abstractmethod
def create_product(self):
pass
class ConcreteFactoryA(Factory):
def create_product(self):
return ConcreteProductA()
class ConcreteFactoryB(Factory):
def create_product(self):
return ConcreteProductB()
if __name__ == '__main__':
# 使用工厂方法模式创建对象
concrete_a = ConcreteFactoryA().create_product()
concrete_a.do_something() # view https://mp.weixin.qq.com/s/0yqGBPbOI6QxHqK17WxU8Q
concrete_b = ConcreteFactoryB().create_product()
concrete_b.do_something() # view https://blog.youkuaiyun.com/zhouruifu2015/
在上面的示例中,我们定义了一个抽象产品类Product,它定义了产品的接口。然后我们定义了两个具体产品类ConcreteProductA和ConcreteProductB,它们分别实现了抽象产品类的接口。接着,我们定义了一个抽象工厂类Factory,它定义了创建产品的接口。最后,我们定义了两个具体工厂类ConcreteFactoryA和ConcreteFactoryB,它们分别实现了抽象工厂类的接口,并根据需要创建相应的产品。
代码示例3
import settings
class Factory:
"""工厂类"""
def get_article(self):
return self.article_addr
class GIT(Factory):
def __init__(self):
self.article_addr = settings.GIT
def article(self):
print("Gitee")
class WECHAT(Factory):
def __init__(self):
self.article_addr = settings.BLOG
def article(self):
print("WeChat")
class ArticleInterfaceFactory:
"""
接口基类
"""
def create(self):
"""把要创建的工厂对象装配进来"""
raise NotImplementedError
class ArticleGit(ArticleInterfaceFactory):
def create(self):
return GIT()
class ArticleWeChat(ArticleInterfaceFactory):
def create(self):
return WECHAT()
if __name__ == '__main__':
git_interface = ArticleGit()
git_obj = git_interface.create()
git_obj.article() # Gitee
print(git_obj.get_article()) # https://gitee.com/SteveRocket
wechat_interface = ArticleWeChat()
wechat_obj = wechat_interface.create()
wechat_obj.article() # WeChat
print(wechat_obj.get_article()) # https://mp.weixin.qq.com/s/0yqGBPbOI6QxHqK17WxU8Q
代码示例4:解析不同类型的文件
import xml.etree.ElementTree as etree
import json
class JSONConnector:
def __init__(self, filepath):
"""
解析json文件的工厂
"""
self.data = dict()
with open(filepath, mode='r', encoding='utf-8') as f:
self.data = json.load(f)
@property
def parsed_data(self):
return self.data
class XMLConnector:
def __init__(self, filepath):
"""
解析XML文件的工厂
"""
self.tree = etree.parse(filepath)
@property
def parsed_data(self):
return self.tree
def connection_factory(filepath):
if filepath.endswith('json'):
connector = JSONConnector
elif filepath.endswith('xml'):
connector = XMLConnector
else:
raise ValueError('Cannot connect to {}'.format(filepath))
return connector(filepath)
def connect_to(filepath):
factory = None
try:
factory = connection_factory(filepath)
except ValueError as ve:
print(ve)
return factory
def main():
sqlite_factory = connect_to('data/person.sq3') # Cannot connect to data/person.sq3
print()
xml_factory = connect_to('data/person.xml')
xml_data = xml_factory.parsed_data
parse_str = ".//{}[{}='{}']".format('person', 'firstName', 'SteveRocket')
liars = xml_data.findall(parse_str)
print('found: {} persons'.format(len(liars)))
for liar in liars:
print('first name: {}'.format(liar.find('firstName').text))
print('last name: {}'.format(liar.find('lastName').text))
[print('phone number ({})'.format(p.attrib['type']), p.text) for p in liar.find('phoneNumbers')]
print()
json_factory = connect_to('data/donut.json')
json_data = json_factory.parsed_data
print('found: {} donuts'.format(len(json_data)))
for donut in json_data:
print('name: {}'.format(donut['name']))
[print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]
if __name__ == '__main__':
main()
输出结果
结论
通过上述实例,我们成功地使用工厂方法模式创建了不同类型的动物对象。工厂方法模式将对象的创建延迟到子类中实现,使得客户端代码与具体的产品类解耦,增加了代码的灵活性和可扩展性。在实际开发中,工厂方法模式可以帮助我们根据不同的条件创建不同类型的对象,提高代码的可维护性和可扩展性。
使用工厂方法模式的优点是将对象的创建和使用分离开来,客户端只需要知道工厂类和产品的接口,而不需要知道具体的产品实现。这样可以降低客户端和具体产品类之间的耦合度。工厂方法模式还支持新增产品类和工厂类,而不需要修改已有的代码,符合开闭原则。
抽象工厂、工厂方法、简单工厂之间的区别
抽象工厂模式(Abstract Factory)、工厂方法模式(Factory Method)和简单工厂模式(Simple Factory)都属于创建型设计模式,它们都用于创建对象,但在实现方式和应用场景上有一些区别。
1. 简单工厂模式(Simple Factory)
简单工厂模式通过一个工厂类来创建对象,根据传入的参数或条件决定创建哪种具体对象。
简单工厂模式的优点是可以隐藏对象的创建逻辑,客户端只需要通过工厂类来获取对象即可,不需要关心具体的创建细节。
简单工厂模式的缺点是当需要添加新的具体对象时,需要修改工厂类的代码,违反了开闭原则。
2. 工厂方法模式(Factory Method)
工厂方法模式将对象的创建延迟到子类中实现,每个具体子类都可以创建自己特定的对象。
工厂方法模式通过定义一个抽象的工厂接口和多个具体的工厂子类来实现对象的创建。
工厂方法模式的优点是符合开闭原则,可以通过添加新的具体工厂子类来扩展对象的创建。
工厂方法模式的缺点是客户端需要知道具体的工厂子类,增加了客户端与工厂子类的耦合。
3. 抽象工厂模式(Abstract Factory)
抽象工厂模式通过定义一个抽象的工厂接口和多个具体的工厂类来创建一系列相关或相互依赖的对象。
抽象工厂模式可以创建一组相关的产品对象,而不需要指定具体的工厂子类。
抽象工厂模式的优点是将对象的创建和使用解耦,客户端只需要通过抽象工厂接口来创建对象,不需要关心具体的工厂类和产品类。
抽象工厂模式的缺点是当需要添加新的产品对象时,需要修改抽象工厂接口和所有的具体工厂类,违反了开闭原则。
综上所述,简单工厂模式适用于对象的创建逻辑相对简单,不需要频繁添加新的具体对象;工厂方法模式适用于对象的创建逻辑复杂,需要根据不同的条件创建不同的对象;抽象工厂模式适用于创建一组相关的产品对象,需要将对象的创建和使用解耦。
下一篇我们将介绍《Python设计模式之创建型-抽象工厂模式(Abstract Factory)》。
Python专栏
https://blog.youkuaiyun.com/zhouruifu2015/category_5742543
更多精彩,关注我公号,一起学习、成长
CTO Plus
一个有深度和广度的技术圈,技术总结、分享与交流,我们一起学习。 涉及网络安全、C/C++、Python、Go、大前端、云原生、SRE、SDL、DevSecOps、数据库、中间件、FPGA、架构设计等大厂技术。 每天早上8点10分准时发文。
306篇原创内容
公众号
标准库系列-推荐阅读:
推荐阅读:
最后,不少粉丝后台留言问加技术交流群,之前也一直没弄,所以为满足粉丝需求,现建立了一个关于Python相关的技术交流群,加群验证方式必须为本公众号的粉丝,群号如下: