Ответ 1
Почему бы не перегрузить метод getEmployeeName (??)?
getEmployeeName (int BatchID) getEmployeeName (объект SSN) (плохая идея)
getEmployeeName (строковая электронная почта)
и др.
Кажется хорошим для меня "много".
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, который будет предоставлен клиентам.
Почему бы не перегрузить метод getEmployeeName (??)?
getEmployeeName (int BatchID) getEmployeeName (объект SSN) (плохая идея)
getEmployeeName (строковая электронная почта)
и др.
Кажется хорошим для меня "много".
Вы можете использовать что-то вроде этого:
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.
Я бы пошел с "многими" подходами. Это кажется более интуитивным для меня и менее подверженным ошибкам.
Мне не нравится getXByY() - это может быть круто в PHP, но мне просто не нравится в Java (ymmv).
Я бы перегрузил, если у вас нет свойств одного и того же типа данных. В этом случае я бы сделал что-то похожее на ваш второй вариант, но вместо использования ints я использовал Enum для обеспечения безопасности и ясности типов. И вместо байта [], я бы использовал Object (из-за autoboxing, это также работает для примитивов).
Эти методы являются прекрасным примером использования перегрузки.
getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)
Если методы имеют общую обработку внутри, просто напишите еще один getEmplyeeNameImpl (...) и извлеките там общий код, чтобы избежать дублирования
Первый вариант, без вопросов. Будьте ясны. Это значительно поможет в ремонтопригодности, и на самом деле нет недостатков.
@Stephan: трудно перегрузить такой случай (в общем случае), поскольку типы параметров могут быть недискриминационными, например,
См. также два метода getEmployeeNameBySSN, getEmployeeNameByEmailId в исходной публикации.
Иногда может быть более удобно использовать шаблон спецификации.
Например: 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);
Я буду использовать явные имена методов. Все, кто поддерживает этот код и меня позже, поймут, что делает этот метод, не записывая комментарии xml.
Я бы использовал первый вариант или перегрузил его в этом случае, увидев, что у вас есть 4 разных сигнатуры параметра. Тем не менее, конкретное помогает понять код через 3 месяца.
Первое, вероятно, самое лучшее в Java, поскольку оно является типичным (в отличие от другого). Кроме того, для "нормальных" типов второе решение, по-видимому, обеспечивает только громоздкое использование для пользователя. Однако, поскольку вы используете Object как тип для SSN (который имеет семантическое значение вне Object), вы, вероятно, не уйдете с этим типом API.
В общем, в этом конкретном случае я бы использовал этот подход со многими геттерами. Если у всех идентификаторов есть свой тип класса, я мог бы пойти вторым путем, но переключился внутри класса вместо назначенного/определяемого приложением идентификатора типа.
Является ли логика внутри каждого из этих методов в значительной степени одинаковой?
Если это так, единственный метод с параметром идентификатора может иметь больше смысла (простой и уменьшающий повторяющийся код).
Если логика/процедуры сильно различаются между типами, может быть предпочтительным метод для каждого типа.
Как и другие, первый вариант кажется хорошим. Второй может иметь смысл, когда вы пишете код, но когда кто-то еще приходит позже, сложнее понять, как использовать код. (Я знаю, у вас есть комментарии, и вы всегда можете углубиться в код, но GetemployeeNameById более понятен)
Примечание: Btw, использование Enums может быть чем-то рассмотрено в некоторых случаях.
В таком тривиальном случае я бы пошел с перегрузкой. То есть:
getEmployeeName( int batchID );
getEmployeeName( Object SSN );
etc.
Только в особых случаях я бы указал тип аргумента в имени метода, т.е. если тип аргумента трудно определить, если существует несколько типов аргументов, то тот же тип данных (batchId и employeeId, оба int), или если методы для извлечения сотрудника радикально различаются для каждого типа аргумента.
Я не понимаю, почему я когда-либо использовал этот
getEmployeeName(int typeOfIdentifier, byte[] identifier)
поскольку для вызова значения на основе typeOfIdentifier требуется как вызывающий, так и вызывающий. Плохой дизайн.
Если вы переписываете вопрос, вы можете задать вопрос:
"SELECT name FROM..."
"SELECT SSN FROM..."
"SELECT email FROM..."
против
"SELECT * FROM..."
И я думаю, что ответ на этот вопрос прост, и все это знают.
Что произойдет, если вы измените класс Employee? Например: вы должны удалить письмо и добавить новый фильтр, например, отдел. Со вторым решением у вас есть огромный риск не заметить никаких ошибок, если вы просто измените порядок идентификаторов "константы". При первом решении вы всегда заметите, используете ли вы метод в некоторых давно забытых классах, которые вы, в противном случае, могли бы забыть изменить на новый идентификатор.
Я лично предпочитаю иметь явное именование "... ByRoomNumber", потому что, если вы закончите со многими "перегрузками", вы в конечном итоге внесите нежелательные ошибки. Быть явным является imho лучшим способом.
Я согласен со Стефаном: одна задача, одно имя метода, даже если вы можете сделать это несколькими способами. Функция перегрузки метода была предоставлена именно для вашего случая.
И избегайте вашего второго решения любой ценой. Он пахнет "твоей старой пустотой" от С ". Аналогично, передача Java" Object "почти такая же белая, как C" void *".
Если у вас хороший дизайн, вы сможете определить, можете ли вы использовать подход перегрузки или если вы столкнулись с проблемой, где, если вы перегрузитесь, у вас будет два метода с тем же тип параметра.
Перегрузка сначала кажется лучшим способом, но если вы в конечном итоге не сможете добавить метод в будущем, а испортить вещи, назвав его, это будет проблемой.
Лично я за подход уникального имени для метода, таким образом, вы не столкнетесь с проблемами позже, пытаясь перегрузить один и тот же метод Object. Кроме того, если бы кто-то расширил ваш класс в будущем и реализовал другое void getEmployeeName (имя строки), он не переопределит ваш.
Подводя итог, перейдите с уникальным именем метода для каждого метода, перегрузка может вызвать проблемы в конечном итоге.
Развязка между поисковым процессом и критериями поиска, которые предлагает jrudolf, в его примере отличная. Интересно, почему это не самое голосованное решение. Я что-то пропустил?
Я бы пошел с Объекты запроса. Они хорошо работают для прямого доступа к таблицам. Если вы ограничены хранимыми процедурами, они теряют часть своей мощности, но вы все равно можете заставить ее работать.
Вставьте все свои параметры в перечисление, у вас есть что-то вроде следующего
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
}
Вы думаете, 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 для сигнализации неправильного ввода.
Документируйте это, чтобы клиент знал, какие объекты ожидать. Или создайте свои собственные обертки. Я предпочитаю первый вариант.