Получить методы: один против многих

getEmployeeNameByBatchId (int batchID)
getEmployeeNameBySSN (SSN объекта)
getEmployeeNameByEmailId (String emailID)
getEmployeeNameBySalaryAccount (SalaryAccount salaryAccount)

или же

getEmployeeName (int typeOfIdentifier, byte [] identifier) ​​-> В этих методах typeOfIdentifier сообщает, является ли идентификатор идентификатором batchID / SSN / emailID / salaryAccount

Какой из вышеперечисленных способов лучше реализовать метод get?

Эти методы будут в сервлете, а вызовы будут выполняться из API, который будет предоставлен клиентам.

Пусть религиозные баталии ... НАЧИНАЮТСЯ !!!

CodeChimp 20.09.2013 20:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
10
1
699
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Я бы выбрал подход «многие». Мне он кажется более интуитивным и менее подверженным ошибкам.

Менее подвержен ошибкам, но, вероятно, более подвержен дублированию кода.

jrudolph 17.09.2008 13:47
Ответ принят как подходящий

Почему бы не перегрузить метод getEmployeeName (??)?

getEmployeeName (int BatchID)
getEmployeeName (SSN объекта) (плохая идея)
getEmployeeName (строка электронной почты)
и Т. Д.

Мне кажется, что это хороший подход «многие».

Может быть, не всегда быть гибким, если есть несколько полей одного и того же типа данных. getEmployeeName (строка электронной почты) getEmployeeName (строка паспортного номера) getEmployeeName (строка phoneNumber) ....

icelava 17.09.2008 12:01

Много. Более читабельный. Если вам нужны все эти варианты, напишите их все.

Gishu 17.09.2008 12:07

Это не лучший подход, поскольку тогда у вас не может быть критериев одного типа.

jrudolph 17.09.2008 12:12

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

rpattabi 21.09.2008 13:15

ragu прав насчет этого: если «email» и «паспортный номер» относятся к одному и тому же типу, то, возможно, это повод дать им настоящий тип. +1.

paercebal 21.09.2008 14:46

Затем возьмите имя и фамилию, вы, вероятно, не стали бы вводить тип для каждого из них, не так ли? Это только совпадение, что типы могут использоваться для различения ролей свойств объекта.

jrudolph 21.09.2008 17:19

Я бы использовал первый вариант или перегрузил его в этом случае, поскольку у вас есть 4 разных сигнатуры параметров. Однако конкретика помогает понять код через 3 месяца.

Первый вариант, без вопросов. Будьте откровенны. Это очень поможет в ремонтопригодности, и на самом деле нет никаких недостатков.

Вероятно, у вас будет 4 почти похожих метода. Это больше для поддержания не меньше ...

jrudolph 17.09.2008 12:14

Ваше определение ремонтопригодности отличается от моего.

Aaron Jensen 02.10.2008 20:22

Первый, вероятно, лучший в Java, учитывая, что он безопасен по типу (в отличие от другого). Кроме того, для «обычных» типов второе решение, кажется, только затрудняет использование пользователем. Однако, поскольку вы используете Object в качестве типа для SSN (который имеет семантическое значение, выходящее за рамки Object), вам, вероятно, не сойдет с рук этот тип API.

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

В основном ли одинакова логика внутри каждого из этих методов?

Если это так, единственный метод с параметром идентификатора может иметь больше смысла (простой и сокращающий повторяющийся код).

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

@Stephan: сложно перегрузить такой случай (в общем), потому что типы параметров могут не быть дискриминационными, например,

  • getEmployeeNameByBatchId (int batchId)
  • getEmployeeNameByRoomNumber (int roomNumber)

См. Также два метода getEmployeeNameBySSN и getEmployeeNameByEmailId в исходной публикации.

Как предполагали другие, первый вариант кажется хорошим. Второй вариант может иметь смысл, когда вы пишете код, но когда позже появляется кто-то другой, становится сложнее понять, как использовать код. (Я знаю, у вас есть комментарии, и вы всегда можете углубиться в код, но GetemployeeNameById более понятен)

Примечание. Между прочим, в некоторых случаях следует учитывать использование Enums.

Вы думаете о C / C++.

Используйте объекты вместо байта идентификатора (или int).

Мое плохое, подход с перегрузкой лучше, а использование SSN в качестве первичного ключа не так хорошо

public ??? getEmployeeName(Object obj){

if (obj instanceof Integer){

  ...

} else if (obj instanceof String){

...

} else if .... // and so on


} else throw SomeMeaningFullRuntimeException()

return employeeName
}

Я думаю, что для сигнализации неправильного ввода лучше использовать Unchecked Exceptions.

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

Зачем полагаться на исключения времени выполнения, если можно обеспечить статическую безопасность времени компиляции?

jrudolph 17.09.2008 12:15

Я согласен с Джрудольфом. То, что вы кодируете, является чистым старым "программированием переключателя C". Хотя это лучше, чем массив байтов, это не лучшее решение.

paercebal 17.09.2008 12:22

В таком тривиальном случае я бы пошел с перегрузкой. То есть:

getEmployeeName( int batchID );
getEmployeeName( Object SSN );

etc.

Только в особых случаях я мог бы указать тип аргумента в имени метода, т.е. если тип аргумента трудно определить, есть ли несколько типов аргументов, которые имеют один и тот же тип данных (batchId и employeeId, оба int), или если методы получения сотрудника радикально различаются для каждого типа аргумента.

Я не понимаю, зачем я когда-либо использовал это

getEmployeeName(int typeOfIdentifier, byte[] identifier)

поскольку он требует, чтобы и вызываемый, и вызывающий объект приводили значение на основе typeOfIdentifier. Плохой дизайн.

Если вы переписываете вопрос, вы можете в итоге спросить:

"ВЫБРАТЬ имя ИЗ ..."
«ВЫБРАТЬ SSN ИЗ ...»
"ВЫБРАТЬ Е-mail ОТ ..."
против
"ВЫБРАТЬ ИЗ ..."

Думаю, ответ на этот вопрос прост, и все это знают.

Что произойдет, если вы измените класс Employee? Например: вам нужно удалить электронную почту и добавить новый фильтр, например отдел. Со вторым решением у вас есть огромный риск не заметить никаких ошибок, если вы просто измените порядок «констант» идентификатора int. С первым решением вы всегда заметите, используете ли вы метод в некоторых давно забытых классах, которые иначе вы бы забыли изменить на новый идентификатор.

Эти методы являются прекрасным примером использования перегрузки.

getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)

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

Но строка «getEmployeeName (Object SSN)» заходит слишком далеко ... Тип «Object» сделает почти любую другую перегрузку бессмысленной (очень похоже на ужасный <code> void * </code> из C.

paercebal 21.09.2008 14:51

Мне не нравится getXByY () - это может быть круто в PHP, но мне просто не нравится в Java (ymmv).

Я бы пошел с перегрузкой, если у вас нет свойств того же типа данных. В этом случае я бы сделал что-то подобное вашему второму варианту, но вместо использования целых чисел я бы использовал Enum для безопасности типов и ясности. И вместо byte [] я бы использовал Object (из-за автобокса это также работает для примитивов).

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

Вы можете использовать что-то вроде этого:

interface Employee{
    public String getName();
    int getBatchId();
}
interface Filter{
    boolean matches(Employee e);
}
public Filter byName(final String name){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getName().equals(name);
        }
    };
}
public Filter byBatchId(final int id){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getBatchId() == id;
        }
    };
}
public Employee findEmployee(Filter sel){
    List<Employee> allEmployees = null;
    for (Employee e:allEmployees)
        if (sel.matches(e))
            return e;
    return null;
}
public void usage(){
    findEmployee(byName("Gustav"));
    findEmployee(byBatchId(5));
}

Если вы выполняете фильтрацию с помощью SQL-запроса, вы должны использовать интерфейс Filter для составления предложения WHERE.

Преимущество этого подхода в том, что вы можете легко комбинировать два фильтра:

public Filter and(final Filter f1,final Filter f2){
    return new Filter(){
        public boolean matches(Employee e) {
            return f1.matches(e) && f2.matches(e);
        }
    };
}

и используйте это так:

findEmployee(and(byName("Gustav"),byBatchId(5)));

То, что вы получаете, похоже на API Criteria в Hibernate.

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

Josh 20.09.2008 01:27

Перебор. Речь идет о аксессорах, которые уже являются методами доступа к закрытым полям. Некоторые люди утверждают, что это уже слишком много накладных расходов (и они ошибаются). Вы предлагаете полную структуру фильтров ... Пользователь хочет только имя сотрудника ... :-)

paercebal 21.09.2008 14:49

Конечно, вы должны учитывать сложность такого подхода. Но я бы предпочел такое абстрактное (и явное) решение тому, которое дублирует код и легко расширяется.

jrudolph 21.09.2008 17:24

Иногда удобнее использовать шаблон спецификации.

Например: GetEmployee (спецификация ISpecification <Employee>)

А затем начните определять свои спецификации ...

Имя Спецификация: IS Спецификация <Сотрудник>
{
имя частной строки;
public NameSpecification (строковое имя) {this.name = name; }
public bool IsSatisFiedBy (сотрудник-сотрудник) {return employee.Name == this.name; }
}

NameSpecification spec = новый NameSpecification ("Tim");
Сотрудник tim = MyService.GetEmployee (spec);

Я согласен со Стефаном: одна задача, одно название метода, даже если вы можете сделать это несколькими способами. Возможность перегрузки метода предусмотрена именно для вашего случая.

  • getEmployeeName (int BatchID)
  • getEmployeeName (строковый адрес электронной почты)
  • и Т. Д.

И избегать ваше второе решение любой ценой. Пахнет "твоей старой пустотой * C". Точно так же передача Java «Object» - это почти такой же плохой стиль, как и C «void *».

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

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

Лично я бы за подход с уникальным именем для каждого метода, таким образом, вы не столкнетесь с проблемами позже, пытаясь перегрузить методы одного и того же параметра Object. Кроме того, если кто-то расширил ваш класс в будущем и реализовал другой void getEmployeeName (String name), он не переопределил бы ваш.

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

Я буду использовать явные имена методов. Каждый, кто поддерживает этот код, и я позже поймут, что делает этот метод, без необходимости писать комментарии в формате xml.

вставьте все свои параметры в перечисление, у них будет что-то вроде следующего

GetEmployeeName(Enum identifier)
{
    switch (identifier)
    case eBatchID:
    {
        // Do stuff
    }
    case eSSN:
    {
    }
    case eEmailId:
    {
    }
    case eSalary:
    {
    }
    default:
    {
        // No match
        return 0;
    }
}

enum Identifier
{
    eBatchID,
    eSSN,
    eEmailID,
    eSalary
}

Это одновременно кошмарное обслуживание и противоположная философия большинства современных языков. Никогда и никогда не кодируйте таким образом.

paercebal 21.09.2008 14:41

Разделение между процессом поиска и критериями поиска, которые предлагает Джрудольф в своем примере, отличное. Интересно, почему это не самое популярное решение. Я что-то упускаю?

Потому что это хорошая идея для фреймворка. Но если вопрос касается соглашения об именах средств доступа, вы не хотите создавать экземпляры 10 объектов и делать 10 сравнений только для того, чтобы получить какое-то имя. Таким образом, решение "jrudolf" можно считать излишним в большинстве случаев, а настоящий правильный - в некоторых других.

paercebal 21.09.2008 14:57

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

Другие вопросы по теме