python中的工厂方法

python中的工厂方法,python,Python,我正在为以下小项目工作: 简而言之,它旨在更轻松地管理许多不同的项目。 其中一个有用的方法是自动检测我正在处理的项目类型,正确设置一些命令 目前,我正在使用一个classmethod“match”函数和一个detect函数,它迭代各种“match”。 我肯定有更好的设计,但找不到 有什么想法吗 class ProjectType(object): build_cmd = "" @classmethod def match(cls, _): return

我正在为以下小项目工作:

简而言之,它旨在更轻松地管理许多不同的项目。 其中一个有用的方法是自动检测我正在处理的项目类型,正确设置一些命令

目前,我正在使用一个classmethod“match”函数和一个detect函数,它迭代各种“match”。 我肯定有更好的设计,但找不到

有什么想法吗

class ProjectType(object):
    build_cmd = ""

    @classmethod
    def match(cls, _):
        return True


class PythonProject(ProjectType):
    build_cmd = "python setup.py develop --user"

    @classmethod
    def match(cls, base):
        return path.isfile(path.join(base, 'setup.py'))


class AutoconfProject(ProjectType):
    #TODO: there should be also a way to configure it
    build_cmd = "./configure && make -j3"

    @classmethod
    def match(cls, base):
        markers = ('configure.in', 'configure.ac', 'makefile.am')
        return any(path.isfile(path.join(base, x)) for x in markers)


class MakefileOnly(ProjectType):
    build_cmd = "make"

    @classmethod
    def match(cls, base):
        # if we can count on the order the first check is not useful
        return (not AutoconfProject.match(base)) and \
            (path.isfile(path.join(base, 'Makefile')))


def detect_project_type(path):
    prj_types = (PythonProject, AutoconfProject, MakefileOnly, ProjectType)
    for p in prj_types:
        if p.match(path):
            return p()

对我来说,这看起来不错,不过我会做两个改进

1-使用元类自动收集所有项目类型,而不是手动列出它们,这将避免错误地丢失某些项目类型或具有错误的顺序,例如

class ProjectTypeManger(type):
    klasses = []
    def __new__(meta, classname, bases, classDict):
        klass = type.__new__(meta, classname, bases, classDict)
        meta.klasses.append(klass)
        return klass

    @classmethod
    def detect_project_type(meta, path):
        for p in meta.klasses:
            if p.match(path):
                return p()

class ProjectType(object):
    __metaclass__ = ProjectTypeManger
    build_cmd = ""

    @classmethod
    def match(cls, _):
        return None
2-
match
方法应该返回对象本身,而不是true/false,这样类就可以任意配置对象+您可以调用基类匹配方法,例如
MakefileOnly
可以从
AutoconfProject
派生,以便它首先检查基类是否有任何匹配,但不确定这种继承是否有意义

class MakefileOnly(AutoconfProject):
    build_cmd = "make"

    @classmethod
    def match(cls, base):
        ret = super(MakefileOnly, cls).match(base)
        if ret is not None:
            return ret
        if path.isfile(path.join(base, 'Makefile')):
            return cls()

        return None

这是将工厂函数作为类方法的合理使用

一个可能的改进是让所有类从一个父类继承,该父类将有一个classmethod,该classmethod合并了detect\u project\u type中的所有逻辑

也许这样的方法会奏效:

class ProjectType(object):
    build_cmd = ""
    markers = []

    @classmethod
    def make_project(cls, path):
        prj_types = (PythonProject, AutoconfProject, MakefileOnly, ProjectType)
        for p in prj_types:
            markers = p.markers
            if any(path.isfile(path.join(path, x)) for x in markers):
                return p()

class PythonProject(ProjectType):
    build_cmd = "python setup.py develop --user"
    markers = ['setup.py']

class AutoconfProject(ProjectType):
    #TODO: there should be also a way to configure it
    build_cmd = "./configure && make -j3"
    markers = ['configure.in', 'configure.ac', 'makefile.am']

class MakefileOnly(ProjectType):
    build_cmd = "make"
    markers = ['Makefile']

在这一点上,我想我应该让
make_project
作为一个普通函数放在类之外。在我看来,它允许对所有事物的命名更自然。此外,虽然“复杂性必须有所提高”,但我不喜欢所有子类的元组都是父类中保存的信息的想法。谢谢。我也同意把make_项目放在外面,因为我们实际上并没有使用“cls”参数来make_项目。所以我们不必记住把列表中的每个类按顺序排列,现在我们必须记住用元类标记每个类?总体来说,这可能更容易正确,但似乎完全忘记一个类也同样容易,加上工作现在分布在几个类中…@Karl Knechtel你不必标记每个类,只标记一个,基类ProjectType谢谢我喜欢这个解决方案,然而,如果我只有3-4个类,那么更多的是为元类添加的代码,而不是实际的增益。。。但是,每当我有更多的课程时,我肯定会使用这个技巧。