getEmployeeNameByBatchId (int batchID)
getEmployeeNameBySSN (SSN объекта)
getEmployeeNameByEmailId (String emailID)
getEmployeeNameBySalaryAccount (SalaryAccount salaryAccount)
или же
getEmployeeName (int typeOfIdentifier, byte [] identifier) -> В этих методах typeOfIdentifier сообщает, является ли идентификатор идентификатором batchID / SSN / emailID / salaryAccount
Какой из вышеперечисленных способов лучше реализовать метод get?
Эти методы будут в сервлете, а вызовы будут выполняться из API, который будет предоставлен клиентам.
Я бы выбрал подход «многие». Мне он кажется более интуитивным и менее подверженным ошибкам.
Менее подвержен ошибкам, но, вероятно, более подвержен дублированию кода.
Почему бы не перегрузить метод getEmployeeName (??)?
getEmployeeName (int BatchID) getEmployeeName (SSN объекта) (плохая идея)
getEmployeeName (строка электронной почты)
и Т. Д.
Мне кажется, что это хороший подход «многие».
Может быть, не всегда быть гибким, если есть несколько полей одного и того же типа данных. getEmployeeName (строка электронной почты) getEmployeeName (строка паспортного номера) getEmployeeName (строка phoneNumber) ....
Много. Более читабельный. Если вам нужны все эти варианты, напишите их все.
Это не лучший подход, поскольку тогда у вас не может быть критериев одного типа.
Я считаю, что это хороший подход. Если есть проблема с использованием определенного типа для двух разных вещей, это фактически указывает на недостаток в конструкции. emailId, вероятно, должен принадлежать структуре / классу, а не строке, как в случае с номером телефона и т. д.
ragu прав насчет этого: если «email» и «паспортный номер» относятся к одному и тому же типу, то, возможно, это повод дать им настоящий тип. +1.
Затем возьмите имя и фамилию, вы, вероятно, не стали бы вводить тип для каждого из них, не так ли? Это только совпадение, что типы могут использоваться для различения ролей свойств объекта.
Я бы использовал первый вариант или перегрузил его в этом случае, поскольку у вас есть 4 разных сигнатуры параметров. Однако конкретика помогает понять код через 3 месяца.
Первый вариант, без вопросов. Будьте откровенны. Это очень поможет в ремонтопригодности, и на самом деле нет никаких недостатков.
Вероятно, у вас будет 4 почти похожих метода. Это больше для поддержания не меньше ...
Ваше определение ремонтопригодности отличается от моего.
Первый, вероятно, лучший в Java, учитывая, что он безопасен по типу (в отличие от другого). Кроме того, для «обычных» типов второе решение, кажется, только затрудняет использование пользователем. Однако, поскольку вы используете Object в качестве типа для SSN (который имеет семантическое значение, выходящее за рамки Object), вам, вероятно, не сойдет с рук этот тип API.
В общем, в этом конкретном случае я бы использовал подход со многими геттерами. Если все идентификаторы имеют свой собственный тип класса, я мог бы пойти вторым путем, но переключиться на класс внутри, а не на предоставленный / определяемый приложением идентификатор типа.
В основном ли одинакова логика внутри каждого из этих методов?
Если это так, единственный метод с параметром идентификатора может иметь больше смысла (простой и сокращающий повторяющийся код).
Если логика / процедуры сильно различаются между типами, может быть предпочтительным метод для каждого типа.
@Stephan: сложно перегрузить такой случай (в общем), потому что типы параметров могут не быть дискриминационными, например,
См. Также два метода 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.
Задокументируйте это, чтобы покупатель знал, чего ожидать. Или создайте свои собственные обертки. Я предпочитаю первый вариант.
Зачем полагаться на исключения времени выполнения, если можно обеспечить статическую безопасность времени компиляции?
Я согласен с Джрудольфом. То, что вы кодируете, является чистым старым "программированием переключателя C". Хотя это лучше, чем массив байтов, это не лучшее решение.
В таком тривиальном случае я бы пошел с перегрузкой. То есть:
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.
Мне не нравится 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.
Это отличный подход (я бы лично использовал и использовал его), но с одним исключением. Действительно подумайте заранее, нужен ли вам весь этот дополнительный код для чего-то настолько простого. Иногда лучше просто.
Перебор. Речь идет о аксессорах, которые уже являются методами доступа к закрытым полям. Некоторые люди утверждают, что это уже слишком много накладных расходов (и они ошибаются). Вы предлагаете полную структуру фильтров ... Пользователь хочет только имя сотрудника ... :-)
Конечно, вы должны учитывать сложность такого подхода. Но я бы предпочел такое абстрактное (и явное) решение тому, которое дублирует код и легко расширяется.
Иногда удобнее использовать шаблон спецификации.
Например: 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);
Я согласен со Стефаном: одна задача, одно название метода, даже если вы можете сделать это несколькими способами. Возможность перегрузки метода предусмотрена именно для вашего случая.
И избегать ваше второе решение любой ценой. Пахнет "твоей старой пустотой * 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
}
Это одновременно кошмарное обслуживание и противоположная философия большинства современных языков. Никогда и никогда не кодируйте таким образом.
Разделение между процессом поиска и критериями поиска, которые предлагает Джрудольф в своем примере, отличное. Интересно, почему это не самое популярное решение. Я что-то упускаю?
Потому что это хорошая идея для фреймворка. Но если вопрос касается соглашения об именах средств доступа, вы не хотите создавать экземпляры 10 объектов и делать 10 сравнений только для того, чтобы получить какое-то имя. Таким образом, решение "jrudolf" можно считать излишним в большинстве случаев, а настоящий правильный - в некоторых других.
Я бы пошел с Объекты запроса. Они хорошо подходят для прямого доступа к таблицам. Если вы ограничены хранимыми процедурами, они теряют часть своей мощности, но вы все равно можете заставить их работать.
Пусть религиозные баталии ... НАЧИНАЮТСЯ !!!