首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OOP最佳实践:是否有理由将工厂功能从抽象基类中分离出来?

OOP最佳实践:是否有理由将工厂功能从抽象基类中分离出来?
EN

Software Engineering用户
提问于 2023-04-02 17:51:27
回答 2查看 132关注 0票数 2

考虑以下python3代码:

代码语言:javascript
复制
from abc import ABC, abstractmethod

class Food(ABC):
    _food_factory_map = {}
    _recipes = {}

    @classmethod
    def getFood(cls, foodName):
        return cls._food_factory_map[foodName]()

    @classmethod
    def registerFood(cls, foodName, recipe):
        def callable(foodClass):
            cls._food_factory_map[foodName] = foodClass
            cls._recipes[foodName] = recipe
            return foodClass
        return callable

    def __init__(self):
        print("Starting Food prep")

    @abstractmethod
    def prepareFood(self):
        ...

    def serveFood(self):
        food = self.prepareFood()
        print(food)

@Food.registerFood('Burger', 'Burger Recipe')
class Burger(Food):
    def prepareFood(self):
        return 'Burger is ready!'

@Food.registerFood('Pizza', 'Pizza Recipe')
class Pizza(Food):
    def prepareFood(self):
        return 'Pizza is ready!'

if __name__ == '__main__':
    fs = ('Burger', 'Pizza')
    for f in fs:
        print(f"Food Recipe: {Food._recipes[f]}")
        food = Food.getFood(f)
        food.serveFood()

在这里,抽象基类Food有实现工厂设计模式的类方法。客户端可以使用registerFood注册自己的具体类,并使用getFood检索它们。抽象基类还实现了定义接口的其他抽象和具体方法。

还可以将两个类方法(getFood和registerFood)和两个类成员(_food_factory_map和_recipes)分离为它自己的一个类(FoodFactory)

代码语言:javascript
复制
class FoodFactory(ABC):
    _food_factory_map = {}
    _recipes = {}

    @classmethod
    def getFood(cls, foodName):
        return cls._food_factory_map[foodName]()

    @classmethod
    def registerFood(cls, foodName, recipe):
        def callable(foodClass):
            cls._food_factory_map[foodName] = foodClass
            cls._recipes[foodName] = recipe
            return foodClass
        return callable

然后,所有客户端代码将改为使用FoodFactory而不是Food。

代码语言:javascript
复制
@FoodFactory.registerFood('Pizza', 'Pizza Recipe')
class Pizza(Food):
    def prepareFood(self):
        return 'Pizza is ready!'

if __name__ == '__main__':
    fs = ('Burger', 'Pizza')
    for f in fs:
        print(f"Food Recipe: {FoodFactory._recipes[f]}")
        food = FoodFactory.getFood(f)
        food.serveFood()

这些实现中哪一个更好,为什么?或者使用这两者都是完全合理的?它依赖于语言吗?

我可以考虑的一个优点是,使用第二个方法,可以覆盖__new__ of FoodFactory直接返回适当食物的实例,而不是调用单独的getFood方法。但这种差异在很大程度上似乎是表面上的。

EN

回答 2

Software Engineering用户

发布于 2023-04-02 23:07:14

你的毯子问题

OOP最佳实践:是否有理由将工厂功能从抽象基类中分离出来?

当构造函数不再是当前问题的适当解决方案时,工厂就得到了保证。因此,您可以认为构造函数是一个非常简单的工厂,当构造逻辑变得足够复杂以保证与工厂的产品(即原始类)分离时,您只需要考虑一个工厂(即单独的类)。

所以,要回答你的一般性问题,如果有任何理由把它分开,答案是肯定的。具体来说,在构造逻辑足够复杂的情况下,或者例如,当您需要一个能够动态生成产品的可注入依赖时。

您的具体示例

对于Food来说,知道一组菜谱是没有语义意义的。这是元知识。类似地,你的汽车不包含它自己的建筑蓝图,更不用说其他许多汽车的蓝图了。

我的直觉告诉我,这是一种构图过度继承的违反。更有意义的是,将菜谱集合保存在一个专用的类中(让我们称之为RecipeBook)。

在这里使用继承是错误的构造。您没有使用继承提供的多态性。汉堡包不是菜谱的集合,这也是你的遗产目前所宣称的。

我不是Python,所以我不喜欢编写您的代码片段的改进版本。

票数 4
EN

Software Engineering用户

发布于 2023-04-02 19:00:31

我想说,这里的主要原因是您在工厂中应用了单例模式。

你绝不能有不同的工厂。

你永远不能嘲笑这家工厂。

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/444809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档