Две функции или одна функция с разными параметрами? - PullRequest
4 голосов
/ 08 мая 2009

Это очень общий вопрос «передового опыта», но вот пример.

Допустим, у меня есть приложение для каталогизации фильмов. Я хочу дать своим пользователям возможность указать, скажем, IMDb или Metacritic для их синопсиса / информации о рейтинге.

Должен ли я сделать это:

if (preferredSupplier == "imdb"){
      getIMDbRating(movieName);
}else{
      getMetacriticRating(movieName);
}

Или это:

getRating(movieName, preferredSupplier);

Мне больше нравится второй, но это означает, что функция должна будет следовать совершенно другой логике в зависимости от значения второго параметра (например, для Metacritic может потребоваться очистка экрана, где у IMDb может быть хороший API).

Или мне их объединить? Как и в getRating () действует как функция-обертка и вызывает getIMDbRating () или getMetacriticRating () в зависимости от значения второго параметра.

Ответы [ 11 ]

6 голосов
/ 08 мая 2009

Второй позволяет увеличить количество предпочитаемых поставщиков с течением времени, и вы все еще можете (внутренне) реализовать их как два отдельных метода.

Если бы это был я, я бы посмотрел на два класса (Imdb и Metacritic), оба производные от базового класса RatingProvider и реализующие getRating по-разному.

Или, если бы на мне была шляпа с паттернами, я бы посмотрел на паттерн "Мост".

Только вы знаете, где находится вероятное изменение в вашей системе, и поэтому вы знаете, нужно ли вам ехать в город по этому вопросу, но API, где вы можете получать рейтинги единообразно, независимо от того, откуда они на самом деле пришли, Мне лучше быть API, чем тем, где вы должны принимать эти решения, выбирая один или другой метод.

4 голосов
/ 08 мая 2009

Было бы неплохо иметь класс RatingProvider с методом getRating.

В качестве подклассов могут быть разные провайдеры рейтингов, которые будут иметь собственную реализацию способа получения / обработки рейтингов.

1 голос
/ 08 мая 2009

Я бы определил абстрактный класс MovieDatabase с абстрактным методом getRating, а затем предоставил бы подклассы, которые реализуют метод getRating для различных поставщиков (таких как IMDb, Metacritic).

С помощью этой настройки вы можете написать код, который не зависит от поставщика, то есть ничего не знает о конкретном поставщике. Он просто ожидает экземпляр MovieDatabase и вызывает на нем операцию getRating, не беспокоясь о деталях поставщика или реализации.

Преимущества этого подхода в том, что он более расширяемый. Если вы хотите добавить больше провайдеров или операций, вы можете сделать это в одном месте (класс MovieDatabase и его подклассы), а остальная часть кода должна просто работать.

1 голос
/ 08 мая 2009

Ни одно из решений не является идеальным. Что вам действительно нужно сделать, так это реализовать предпочитаемый объект Suppplier в качестве интерфейса или абстрактного класса с функцией GetRating (string moviename).

Затем реализуйте интерфейс для классов IMDBSupplier и MetaCriticSupplier, и у каждого класса будет своя собственная логика для получения рейтинга. Это делает функцию getRating () полностью независимой от кода, который ее потребляет, что является хорошим, слабо связанным проектом.

В вашем классе, который потребляет поставщиков, ему все равно, какой это тип - он просто вызывает GetRating (). GetRating () не зависит от поставщика для потребителя.

0 голосов
/ 08 мая 2009

Почему ты не можешь сделать что-то вроде

public interface IRating{

  public Rating getRating();
}

public IMDBRating extends Rating

public MetacriticRating extends Rating
0 голосов
/ 08 мая 2009

Если ваши функции возвращают ответ того же типа, перегрузка в одной функции может иметь смысл.

Если ваши функции возвращают очень разные вещи на основе входных данных, вам, вероятно, следует использовать две функции, чтобы различать, что они возвращают разные вещи.

Например, если рейтинг IMDB - 5-звездочная шкала, а рейтинг метакритики - 4-звездочная шкала, вы должны понимать, что с ними следует обращаться по-другому.

Использование отдельных классов поможет прояснить ситуацию, вместо того, чтобы использовать все эти функции.

0 голосов
/ 08 мая 2009

Не будет ли это зависеть от того, как часто вы используете его? Если вы выполняете эту базовую проверку снова и снова по всему коду, то функция избавит вас от повторения этого блока кода.

Однако, если вы используете эту логику только несколько раз здесь и там, тогда может быть яснее просто использовать ее в первом случае.

0 голосов
/ 08 мая 2009

Я полагаю, это зависит от того, как часто вы будете использовать метод (ы), откуда и насколько отличается код. Помните, что основной причиной написания рутины s является то, что они - это верно - рутина . То есть подпрограмма должна содержать код, который вы хотите использовать повторно, и должна быть написана таким образом, чтобы его было легко использовать повторно.

С учетом сказанного, если бы я сталкивался с вашим примером (и занимался кодированием на C #), я, вероятно, в конечном итоге создал бы enum для различных типов поиска в БД, а затем имел бы один метод-обертку, принимающий такой enum в качестве аргумента и из метода-оболочки вызовите другой метод сбора данных - аналогично тому, что вы предложили в конце вашего поста, но не со строкой в ​​качестве ввода.

0 голосов
/ 08 мая 2009

Второй вариант лучше (b.t.w в OO называется Factory). Дайте ему поведение по умолчанию, и в нем вызовите разные функции для каждого провайдера.

0 голосов
/ 08 мая 2009

Я бы предпочел вашу последнюю идею: использовать оба. Наличие функции, которая принимает источник в качестве параметра, позволяет очень легко написать много кода, который переключается от поставщика к поставщику с простым изменением значения (возможно, из пользовательского интерфейса). У вас также есть удобные функции одного поставщика для вызова, если / когда вы намереваетесь позвонить фиксированному, известному поставщику.

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