工厂模式——使用静态方法进行选择

Factory pattern - choosing using static method

我想在我的 python 代码中为两种不同的文件格式使用工厂模式。 是否可以定义一个静态方法来选择我的新 class,而无需在基础 class 中定义 initnew ]?

类似于:

    Class Field(fileName):

       @static method
       def chooseClass(fileName):
            if '.grb' in fileName:
              return FieldGrib(fileName)
            if '.nc' in fileName:
              return FieldnetCDF(fileName)
            else:
              raise valueError('File format not supported')

是否可以在不调用任何方法的情况下,在调用 Field(fileName) 后立即动态分配新的 class?

下面的答案确实解决了我的问题,但我最终得到了 super 的递归循环,你能帮我指出问题吗?

    class Field(object):

def __new__(cls, fieldFile):
    if '.grb' in fieldFile:
      return FieldGrib(fieldFile)
    else:
       raise ValueError('no support for other formats')

def __init__(self, fieldFile):
    print fieldFile

class FieldGrib(Field):

def __init__(self, fieldFile):
    # read Field, opening fieldFile if required
    super(FieldGrib, self).__init__(fieldFile)

你的工厂模式代码看起来没问题。

对于"dynamically allocate the new class as soon as Field(fileName) is called",你可以简单地做:

def Field(fileName):
    if '.grb' in fileName:
        return FieldGrib(fileName)
    if '.nc' in fileName:
        return FieldnetCDF(fileName)
    else:
        raise ValueError('File format not supported')

或者如果出于某种原因你真的需要 Field 作为 class,你可以按如下方式使用 __new__(确保 Field 是 new-style class,即如果使用 Python 2,继承 object):

class Field(object):
    def __new__(cls, fileName):
        if '.grb' in fileName:
            return FieldGrib(fileName)
        if '.nc' in fileName:
            return FieldnetCDF(fileName)
        else:
            raise ValueError('File format not supported')

关于你的第二个问题,我认为不使用 new 是不可能做你想做的事的,除非你同意将它变成像 ferri 描述的那样的函数.如果您想维护 class 结构,您可以这样做。

Class Field(object):
    def __init___(self):
        pass

    def __new__(cls, filename):
       if '.grb' in fileName:
          return FieldGrib(fileName)
        if '.nc' in fileName:
          return FieldnetCDF(fileName)
        else:
          raise valueError('File format not supported')

class FieldGrib(Object_To_Inherit_From)
    def __init__(self, fileName):
        super().__init__(fileName)
        self.fileName = fileName
        ...etc.

编辑:

如果您想维护基础 class 的功能,您可以更改 FieldGrib class 和 FieldnetCDF class 上的继承 class,因为它们是什么return出厂 class。

编辑 2:

你不能从工厂继承class因为当你调用super时它会再次运行new,进入一个递归循环。工厂 class 就是一个工厂。它不应该继承任何东西。它只是指示 class 到 return。 FieldGrib 和 FieldGrib 应该继承自包含您想要的功能的 class,而不是 Field。如果字段仅用于创建其他内容,您可以创建一个名为

的私有字段 class
class _Field(object):

包含您想要的功能并且可以从中继承。但是不应该直接调用它。

这会将 FieldGrab 变成

class FieldGrib(_Field):