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

getEmployeeNameByBatchId (int batchID)
getEmployeeNameBySSN (Object SSN)
getEmployeeNameByEmailId (String emailID)
getEmployeeNameBySalaryAccount (SalaryAccount payAccount)

или

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

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

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

Ответ 1

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

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

Кажется хорошим для меня "много".

Ответ 2

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

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.

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

NameSpecification: ISpecification <Employee>
{
 имя частной строки;
 public NameSpecification (имя строки) {this.name = name; }
 public bool IsSatisFiedBy (Сотрудник сотрудника) {return employee.Name == this.name; }
}

NameSpecification spec = new NameSpecification ( "Тим" );
Employee tim = MyService.GetEmployee(spec);

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

Является ли логика внутри каждого из этих методов в значительной степени одинаковой?

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

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

Ответ 13

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

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

Ответ 14

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

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

etc.

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

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

getEmployeeName(int typeOfIdentifier, byte[] identifier)

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

Ответ 15

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

"SELECT name FROM..."
"SELECT SSN FROM..."
"SELECT email FROM..."
против
"SELECT * FROM..."

И я думаю, что ответ на этот вопрос прост, и все это знают.

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

Ответ 16

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

Ответ 17

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

  • getEmployeeName (int BatchID)
  • getEmployeeName (String Email)
  • и др.

И избегайте вашего второго решения любой ценой. Он пахнет "твоей старой пустотой" от С ". Аналогично, передача Java" Object "почти такая же белая, как C" void *".

Ответ 18

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

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

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

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

Ответ 19

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

Ответ 20

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

Ответ 21

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

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
}

Ответ 22

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

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

My Bad, подход перегрузки лучше и использование 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 для сигнализации неправильного ввода.

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