2011-11-14 93 views
4

我正在下面的小項目: https://github.com/AndreaCrotti/project-organizer工廠方法在Python

後者以短暫的旨在更輕鬆地管理許多不同的項目。 有用的東西之一是自動檢測我正在處理的項目的種類,正確設置一些命令的方法。

此刻,我正在使用classmethod「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() 

回答

4

這是一個合理的使用工廠函數作爲一個類的方法。

的一種可能的改進是有所有類從這將有一個單一的類方法,納入所有的邏輯在detect_project_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'] 
+1

在這一點上,我想我會讓'make_project'坐在類的外面,只是一個普通的函數。它可以讓所有事情的命名更自然一點。另外,雖然「複雜性需要去某個地方」,但我不認爲我喜歡所有子類的元組都是父類中的信息。 –

+0

非常感謝。我也同意make_project在外面,也因爲我們實際上並沒有真正使用「cls」參數來進行make_project。 –

2

對我來說這看起來不錯,但我會做手工兩個方面的改進

1元類使用自動收集所有ProjectTypes,而不是列出它們,這將避免錯誤地遺漏了一些工程類或具有錯誤的順序例如

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方法應該返回對象本身,而不是真/假,這樣的類可以配置對象反正就是了+你可以調用基類的比賽方法,例如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 
+0

因此而不必記得把每個類列表中,以中,現在我們要記住,以紀念與元類每類?這可能會更容易得到正確的整體,但似乎完全容易忘記一個類,再加上現在的工作分佈在幾個類... –

+1

@Karl Knechtel你不必標記每個類,只有一個,基類ProjectType –

+0

謝謝,我喜歡這個解決方案,但是如果我只有3-4個類,那麼它爲元類添加的代碼比實際獲得的更多......但是,當我有更多的類時,我一定會使用這個技巧。 –