如何重构需要一个参数但都需要相同的两个函数?

时间:2019-03-29 16:18:26

标签: python design-patterns

我有两个方法,除了一个参数外,所有方法都使用相同的参数,并且运行相同的代码,但其中一个方法需要额外一行。我试图确定最好的方法是清理函数,以免重复代码。这是有问题的方法。

我尝试使用try/except子句,但是我觉得那很笨拙且过大。我正在考虑向函数中添加一个参数,该参数说明了意图是创建还是编辑文件,但感觉过于严格。

def create_file(self, file_blob, filename, commit_message, committer_info, branch):
    json_file_data = self._file_data(file_blob, commit_message, committer_info, branch)
    content_url = '{}/{}'.format(self._github_content_url, filename)
    response = self._request(content_url, method='PUT', data=json_file_data)
    self._handle_errors(response)
def edit_file(self, file_blob, filename, commit_message, committer_info, branch):
    file_blob_sha = self._latest_blob_sha_for_file(branch, filename)
    content_url = '{}/{}'.format(self._github_content_url, filename)
    json_file_data = self._file_data(file_blob, commit_message, committer_info, branch, file_blob_sha)
    response = self._request(content_url, method='PUT', data=json_file_data)
    self._handle_errors(response)

3 个答案:

答案 0 :(得分:1)

可重用性有时需要使用函数,因此您可能想要一个私有函数来处理edit_filecreate_file的公共部分,

def _process_file(json_file_data, filename):
    content_url = '{}/{}'.format(self._github_content_url, filename)
    response = self._request(content_url, method='PUT', data=json_file_data)
    self._handle_errors(response)

def create_file(self, file_blob, filename, commit_message, committer_info, branch):
    json_file_data = self._file_data(file_blob, commit_message, committer_info, branch)
    _process_file(json_file_data, filename)

def edit_file(self, file_blob, filename, commit_message, committer_info, branch):
    file_blob_sha = self._latest_blob_sha_for_file(branch, filename)
    json_file_data = self._file_data(file_blob, commit_message, committer_info, branch, file_blob_sha)
    _process_file(json_file_data, filename)

答案 1 :(得分:0)

create_fileedit_file之间的唯一区别是您调用以生成file_blob_sha的值的函数。您可以假装create_file调用了一个返回None的函数(或_file_data的该参数的默认值)。

定义一个通用基本函数,该基本函数将必要的函数用作参数,而不是将其硬编码到create_fileedit_file的主体中。

def _base(self,
          file_blob,
          filename,
          commit_message,
          committer_info,
          branch,
          fn):
    file_blob_sha = fn(branch, filename)

    json_file_data = self._file_data(file_blob, commit_message, committer_info, branch, file_blob_sha)
    content_url = '{}/{}'.format(self._github_content_url, filename)
    response = self._request(content_url, method='PUT', data=json_file_data)
    self._handle_errors(response)

(请注意,主体看起来完全像edit_file;您刚刚用函数参数替换了对self._latest_blob_sha_for_file的硬编码引用。)

每个其他函数然后只需使用适当的函数参数调用_base。对于create_file,这是一个显式函数,将忽略其参数并返回None

def create_file(self, file_blob, filename, commit_message, committer_info, branch):
    return self._base(
        file_blob,
        filename,
        commit_message,
        committer_info,
        branch,
        lambda *args: None)

def edit_file(self, file_blob, filename, commit_message, committer_info, branch):
    return self._base(
        file_blob,
        filename,
        commit_message,
        committer_info, 
        branch,
        self._latest_blob_sha_for_file)

您可以通过定义一个函数来进一步简化样板,该函数通过关闭函数参数来返回。采用这种方法,您尚无权访问self来创建要在edit_file中使用的绑定方法,因此必须将self显式传递给回调函数。

class SomeClass:
    def _make_method(fn):
        def _base(self, file_blob, filename, commit_message, committer_info, branch):
            file_blob_sha = fn(self, branch, filename)

            json_file_data = self._file_data(file_blob, commit_message, committer_info, branch, file_blob_sha)
            content_url = '{}/{}'.format(self._github_content_url, filename)
            response = self._request(content_url, method='PUT', data=json_file_data)
            self._handle_errors(response)
        return _base

    def _latest_blob_sha_for_file(self, branch, filename):
        ...

    create_file = _make_method(lambda *args: None)
    edit_file = _make_method(_latest_blob_sha_for_file)

    del _make_method

请注意,_make_method本身并不是方法。它只是用来定义create_fileedit_file的帮助函数,因此我们在构造类之前将其从类命名空间中删除。

答案 2 :(得分:0)

另一个选择是添加一个新参数:

def manipulate_file(self, file_blob, filename, commit_message, committer_info, branch, edit = False):
    args = [file_blob, filename, commit_message, committer_info, branch]
    if edit:
        file_blob_sha = self._latest_blob_sha_for_file(branch, filename)
        args += [file_blob_sha]
    content_url = '{}/{}'.format(self._github_content_url, filename)
    json_file_data = self._file_data(*args)
    response = self._request(content_url, method='PUT', data=json_file_data)
    self._handle_errors(response)