Предоставляют ли люди несколько механизмов для выполнения одной и той же вещи в API? - PullRequest
4 голосов
/ 15 февраля 2009

Смущает ли разработка API множеством способов достижения одного и того же результата? Например, у меня есть собственная библиотека Date (которая представляет собой простую оболочку для классов Java Date / Calendar, чтобы отличать год-месяц-день , Date от мгновенный , Instant и обеспечивают механизмы для преобразования между ними). Я начал с одного метода, чтобы создать экземпляр Date:

Date.valueOfYearMonthDay(int year, int month, int day);

Но потом я обнаружил, что результирующий код, использующий API, был не очень читабельным. И я добавил:

Date.yearMonthDay(int year, int month, int day)
Date.ymd(int year, int month, int day)
Date.date(int year, int month, int day)

Тогда я начал бегло говорить:

Date.january().the(int day).in(int year);

(я считаю, что свободная версия действительно полезна для создания читабельных тестов). Все эти методы делают идентичные вещи и имеют точный JavaDoc. Я думаю, что я прочитал, что сила perl в том, что каждый программист может точно выбрать, какой метод он / она предпочитает решить. И сила Java в том, что обычно есть только один способ сделать что-то: -)

Каково мнение людей?

Ответы [ 7 ]

7 голосов
/ 15 февраля 2009

Последние 10 лет я занимаюсь научными исследованиями по различным вопросам, связанным с удобством использования API в Java.

Я могу вам сказать, что утверждение о том, что есть один способ сделать что-то в Java, довольно неверно. Часто есть много способов сделать то же самое в Java. И, к сожалению, они часто не соответствуют или задокументированы.

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

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

Еще большая проблема заключается в том, что информация, которую несет имя, больше не имеет смысла. Например, такие вещи, как putLayer и setLayer в колебании, когда один просто обновляет слой, а другой также обновляет (угадайте, какой?), Являются проблемой. Аналогично, getComponentAt и findComponentAt. Другими словами, чем больше способов сделать что-то, тем больше вы запутываете все остальное и уменьшаете «энтропию» вашей существующей функциональности.

Вот хороший пример. Предположим, вы хотите в Java заменить подстроку внутри строки другой строкой. Вы можете использовать String.replace (CharSequence, CharSequence), который работает идеально, как и следовало ожидать, литерал для литерала. Теперь предположим, что вы хотите заменить регулярное выражение. Вы можете использовать Java Matcher и выполнять замену на основе регулярных выражений, и любой сопровождающий поймет, что вы сделали. Однако вы можете просто написать String.replaceAll (String, String), который вызывает версию Matcher. Однако многие ваши сопровождающие могут не знать об этом и не осознавать последствий, в том числе тот факт, что замещающая строка не может содержать «$». Таким образом, замена "USD" на "$" будет хорошо работать с replace (), но вызовет сумасшедшие вещи с replaceAll ().

Возможно, самая большая проблема, однако, заключается в том, что «делать то же самое» редко является проблемой использования одного и того же метода. Во многих местах в Java API (и я уверен, что и в других языках) вы найдете способы сделать «почти то же самое», но с различиями в производительности, синхронизации, изменениях состояния, обработке исключений и т. Д. Например, один вызов будет работать прямо, в то время как другой установит блокировки, а другой изменит тип исключения и т. д. Это рецепт проблемы.

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

5 голосов
/ 15 февраля 2009

Я бы повторил то, что некоторые другие сказали в отношении удобных методов, - это здорово, но сделаю еще один шаг вперед - все "удобные" методы должны в конечном итоге вызывать один и тот же базовый метод . Единственное, что должны делать вспомогательные методы, кроме прокси-запроса, - это принимать или возвращать переменные по-другому.

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

4 голосов
/ 15 февраля 2009

Хорошо предоставить удобные методы, реальная проблема в том, что каждая точка входа начинает вести себя немного по-разному. Вот когда API больше не удобно. Просто вспоминать, какой путь «правильный», - это просто боль, и документация начинает говорить «рекомендуемый путь - это ...»

Если Date.yearMonthDay () начнет проверять дату, а Date.ymd () - нет, это будет проблемой. То же самое происходит, если каждый из них начинает поддерживать разные «функции» - Date.yearMonthDay () может принимать негригорианские даты, а Date.date () может принимать негригорианские даты, если указан 4-й объект, который сообщает календарю типа.

3 голосов
/ 15 февраля 2009

Если они делают то же самое:

 Date.yearMonthDay(int year, int month, int day)
    Date.ymd(int year, int month, int day)
    Date.date(int year, int month, int day)

Я думаю, что это плохая форма. Когда я читаю ваш код, я понятия не имею, какой из них использовать.

Такие вещи, как

canvas.setClipRegion (int left, int top, int right, int bottom); 
canvas.setClipRegion (Rect r);

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

3 голосов
/ 15 февраля 2009

Во-первых, пожалуйста, не изобретайте свою собственную библиотеку дат. Это слишком сложно, чтобы получить право. Если вам абсолютно нечего делать, обязательно прочитайте - и поймите - Календарные вычисления . Не разбираясь в календарных вычислениях, вы рискуете сделать что-то неправильно в непонятных угловых и крайних случаях.

Во-вторых, типичным является множественный доступ к общему базовому методу. Многие методы API библиотеки Java утверждают, что они просто «обертка» вокруг какого-то другого метода класса.

Кроме того, из-за ограничений языка Java вы часто перегружаете имена методов как способ предоставления «необязательных» аргументов для метода.

Методы множественного доступа - прекрасный дизайн.

1 голос
/ 15 февраля 2009

Я считаю, что свободная версия действительно полезна для создания читабельных тестов.

Это немного хлопотно, потому что я волнуюсь, что вы можете тестировать только свободную версию. Если единственная причина, по которой существует methodX (), это то, что вы можете иметь читабельный тест для methodY (), тогда нет причины для существования метода methodX () или methodY (). Вам все еще нужно проверить их изолированно. Ты повторяешь себя без нужды.

Один из руководящих принципов TDD заключается в том, что вы заставляете себя думать о своем API во время написания кода. Решите, какой метод вы хотите, чтобы клиенты вашего API использовали, и избавьтесь от лишних. Пользователи не будут благодарить вас за предоставление удобных методов, они будут ругать вас за то, что вы загромождаете ваш API с помощью на вид бесполезных избыточных методов.

1 голос
/ 15 февраля 2009

Мое личное мнение, что вы должны придерживаться одного метода, чтобы что-то сделать. Все 4 метода ультимативно вызывают один и тот же метод, тогда вам нужен только один из них. Однако если они делают что-то помимо вызова метода, они должны существовать.

так:

// This method should not exist
Data yearMonthDay(final int year, final int month, final int day)
{
    return (valueOfYearMonthDay(year, month, day));
}

Первый метид в дополнение к бесплатной версии будет иметь больше смысла. Но методы yearMonthDay, ymd и date должны идти.

Кроме того, разные языки имеют разные цели. То, что в Perl это означает «смысл», не означает, что в Java это имеет смысл (или C #, или C ++, или C, или Basic, или ...)

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