Как провести рефакторинг двух функций, которые требуют одного и того же параметра, кроме одного? - PullRequest
0 голосов
/ 29 марта 2019

У меня есть два метода, которые принимают все, кроме одного, одинаковые параметры и запускают один и тот же код, за исключением одной дополнительной строки для одного из методов. Я пытаюсь решить, какой лучший подход - очистить функции, чтобы не дублировать код. Вот методы, о которых идет речь.

Я пытался использовать предложение 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 ]

1 голос
/ 29 марта 2019

Иногда для повторного использования вызываются функции, поэтому у вас может быть как частная функция, которая обрабатывает общую часть edit_file и create_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)
0 голосов
/ 29 марта 2019

Другой вариант - добавить новый параметр:

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)
0 голосов
/ 29 марта 2019

Единственная разница между create_file и edit_file - это функция, которую вы вызываете, чтобы получить значение для file_blob_sha.Вы можете сделать вид, что create_file вызвал функцию, которая возвратила None (или любое другое значение по умолчанию для этого параметра, равное _file_data).

Определите общую базовую функцию, которая принимает необходимую функцию в качестве аргумента.вместо жесткого кодирования его в тело create_file или edit_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_file и edit_file, поэтому мы удаляем ее из пространства имен класса до его создания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...