3

我有一些 Python 代码基于从 iCalendar 文件解析的 VEvent 对象创建日历对象。

日历对象只有一个方法,可以在解析事件时添加事件。

现在我想创建一个工厂函数,从文件对象、路径或 URL 创建日历。

我一直在使用iCalendar python 模块,它直接在返回实例的 Class 上实现工厂函数作为类方法:

cal = icalendar.Calendar.from_string(data)

根据我对 Java 的了解,这是 Java 代码中的一种常见模式,尽管我似乎发现更多对工厂方法的引用位于与您实际要从中实例化实例的类不同的类上。

问题是,这也被认为是 Pythonic 吗?还是仅仅创建一个模块级方法作为工厂函数是否被认为更pythonic?

4

5 回答 5

12

[。在将“日历”一系列事件和“事件”(日历上的单个事件)分开时要非常谨慎。在您的问题中,似乎可能存在一些混乱。]

工厂设计模式有很多变体。

  1. 一个独立的便利函数(例如,calendarMaker(data))

  2. 一个单独的类(例如,CalendarParser),它构建您的目标类(日历)。

  3. 一个类级别的方法(例如 Calendar.from_string)方法。

这些有不同的目的。都是 Pythonic,问题是“你是什么意思?” 和“可能会发生什么变化?” 意义就是一切;改变很重要。

便利函数是 Pythonic 的。像 Java 这样的语言不能有自由浮动的函数;你必须在一个类中包装一个孤独的函数。Python 允许你在没有类开销的情况下拥有一个单独的函数。当您的构造函数没有状态更改或替代策略或任何先前操作的记忆时,函数是相关的。

有时人们会定义一个类,然后提供一个方便的函数来创建该类的实例,设置状态和策略的常用参数以及任何其他配置,然后调用该类的单个相关方法。这为您提供了类的状态以及独立函数的灵活性。

使用了类级别的方法模式,但它有局限性。一,它被迫依赖于类级别的变量。由于这些可能会令人困惑,当您需要添加功能(如状态或替代策略)时,作为静态方法的复杂构造函数会遇到问题。请确保您永远不会扩展静态方法。

第二,它与其他类方法和属性或多或少无关。这种from_string只是您的日历对象的许多替代编码之一。您可能有一个from_xml, from_JSON,from_YAML和 on 和 on 。这些都与日历是什么或它的作用无关。这些方法都是关于如何对日历进行编码以进行传输。

您将在成熟的 Python 库中看到工厂与它们创建的东西是分开的。编码(如字符串、XML、JSON、YAML)受制于大量或多或少的随机变化。然而,基本的东西很少改变。

将两个关注点分开。尽可能让编码和表示远离状态和行为。

于 2008-09-22T16:20:38.577 回答
6

不考虑您在某处阅读的某些模式中的深奥差异,现在想在任何地方使用,例如工厂模式,这是pythonic。

大多数时候你会认为@staticmethod 是一种解决方案,使用模块函数可能会更好,除非你在一个模块中填充多个类并且每个类都有相同接口的不同实现,那么最好使用@静态方法

最终,通过@staticmethod 或模块函数创建实例几乎没有什么区别。

我可能会使用类的初始化程序( __init__ ),因为 python 中更被接受的“模式”之一是类的工厂是类初始化。

于 2008-09-22T16:05:25.537 回答
2

恕我直言,模块级方法是一种更清洁的解决方案。它隐藏在 Python 模块系统后面,为它提供了一个独特的命名空间前缀,这是“工厂模式”常用的东西。

于 2008-09-22T16:11:52.793 回答
0

工厂模式有自己的长处和短处。但是,选择一种创建实例的方法通常对您的代码几乎没有实际影响。

于 2008-09-22T16:09:45.123 回答
0

静态方法很少有价值,但类方法可能有用。这取决于您希望类和工厂函数实际执行的操作。

模块中的工厂函数将始终创建“正确”类型的实例(在您的情况下,“正确”始终是“日历”类,但您也可以使其依赖于创建实例的内容在......之外。)

如果您希望类方法不依赖于数据,而是依赖于您调用它的类,请使用类方法。类方法类似于静态方法,您可以在没有实例的情况下在类上调用它,但它接收调用它的类作为第一个参数。这允许您实际创建该类的实例,该实例可能是原始类的子类。classmethod 的一个示例是 dict.fromkeys(),它从键列表和单个值(默认为 None)创建一个 dict。因为它是一个 classmethod,当您将 dict 子类化时,您将完全免费获得“fromkeys”方法. 这是一个如何自己编写 dict.fromkeys() 的示例:

class dict_with_fromkeys(dict):
    @classmethod
    def fromkeys(cls, keys, value=None):
        self = cls()
        for key in keys:
            self[key] = value
        return self
于 2008-09-22T16:30:48.503 回答