tutorials - what is a package in java
Obtener métodos: uno frente a muchos (22)
¿La lógica dentro de cada uno de esos métodos es básicamente la misma?
De ser así, el único método con parámetro identificador puede tener más sentido (simple y reduciendo el código repetido).
Si la lógica / procedimientos varían mucho entre los tipos, puede preferirse un método por tipo.
getEmployeeNameByBatchId (int batchID)
getEmployeeNameBySSN (Object SSN)
getEmployeeNameByEmailId (String emailID)
getEmployeeNameBySalaryAccount (SalaryAccount salaryAccount)
o
getEmployeeName (int typeOfIdentifier, byte [] identifier) -> En este método, typeOfIdentifier dice si el identificador es batchID / SSN / emailID / salaryAccount
¿Cuál de las anteriores es una mejor manera de implementar un método get?
Estos métodos estarían en un Servlet y las llamadas se realizarían desde una API que se proporcionaría a los clientes.
¿Por qué no sobrecargar el método getEmployeeName (??)?
getEmployeeName (int BatchID)
getEmployeeName (SSN del objeto) (mala idea)
getEmployeeName (cadena de correo electrónico)
etc.
Parece un buen ''muchos'' enfoque para mí.
@Stephan: es difícil sobrecargar un caso como este (en general) porque los tipos de parámetros pueden no ser discriminatorios, por ejemplo,
- getEmployeeNameByBatchId (int batchId)
- getEmployeeNameByRoomNumber (int roomNumber)
Consulte también los dos métodos getEmployeeNameBySSN, getEmployeeNameByEmailId en la publicación original.
A veces puede ser más conveniente usar el patrón de especificación .
Ejemplo: especificación GetEmployee (ISpecification <Employee>)
Y luego comience a definir sus especificaciones ...
NameSpecification: ISpecification <Employee>
{
nombre de cadena privada;
public NameSpecification (string name) {this.name = name; }
public bool IsSatisFiedBy (Empleado empleado) {return employee.Name == this.name; }
}
NameSpecification spec = new NameSpecification ("Tim");
Empleado tim = MyService.GetEmployee (spec);
Como otros sugirieron, la primera opción parece ser la buena. Lo segundo puede tener sentido cuando estás escribiendo un código, pero cuando alguien más viene más tarde, es más difícil averiguar cómo usar el código. (Lo sé, usted tiene comentarios y siempre puede profundizar en el código, pero GetemployeeNameById es más fácil de entender)
Nota: Por cierto, el uso de los Enums podría ser algo que se tenga en cuenta en algunos casos.
El desacoplamiento entre el proceso de búsqueda y los criterios de búsqueda que jrudolf propone en su ejemplo es excelente. Me pregunto por qué no es la solución más votada. ¿Extraño algo?
En un caso trivial como este, me iría con la sobrecarga. Es decir:
getEmployeeName( int batchID );
getEmployeeName( Object SSN );
etc.
Solo en casos especiales, especifico el tipo de argumento en el nombre del método, es decir, si el tipo de argumento es difícil de determinar, si hay varios tipos de argumentos que tienen el mismo tipo de datos (batchId y employeeId, ambos int), o si los métodos para recuperar al empleado son radicalmente diferentes para cada tipo de argumento.
No puedo ver por qué alguna vez usaría esto
getEmployeeName(int typeOfIdentifier, byte[] identifier)
ya que requiere que tanto el llamado como la persona que llama emitan el valor en función de typeOfIdentifier. Mal diseño.
Los métodos son un ejemplo perfecto para el uso de la sobrecarga.
getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)
Si los métodos tienen un procesamiento común dentro, simplemente escriba uno más getEmplyeeNameImpl (...) y extraiga allí el código común para evitar la duplicación
No me gusta getXByY () - eso podría ser genial en PHP, pero simplemente no me gusta en Java (ymmv).
Me iría con la sobrecarga, a menos que tenga propiedades del mismo tipo de datos. En ese caso, haría algo similar a tu segunda opción, pero en lugar de usar ints, usaría un Enum para seguridad y claridad. Y en lugar de byte [], usaría Object (debido al autoboxing, esto también funciona para primitivos).
Personalmente prefiero tener el nombre explícito "... ByRoomNumber" porque si terminas con muchas "sobrecargas" eventualmente introducirás errores no deseados. Ser explícito es la mejor manera.
Podrías usar algo como eso:
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));
}
Si realiza el filtrado mediante una consulta SQL, usaría la interfaz de Filter
para redactar una cláusula WHERE.
Lo bueno de este enfoque es que puedes combinar dos filtros fácilmente con:
public Filter and(final Filter f1,final Filter f2){
return new Filter(){
public boolean matches(Employee e) {
return f1.matches(e) && f2.matches(e);
}
};
}
y úsalo así:
findEmployee(and(byName("Gustav"),byBatchId(5)));
Lo que obtienes es similar a la API de Criteria
en Hibernate.
Primera opción, sin dudas. Ser explícito Será de gran ayuda en el mantenimiento y realmente no hay inconvenientes.
Si reescribe la pregunta, puede terminar preguntándose:
"SELECCIONAR nombre FROM ..."
"SELECCIONAR SSN DE ..."
"SELECCIONE EL CORREO DESDE ..."
vs.
"SELECCIONAR DE ..."
Y creo que la respuesta es fácil y todos lo saben.
¿Qué sucede si cambias la clase Empleado? Por ejemplo: debe eliminar el correo electrónico y agregar un nuevo filtro como departamento. Con la segunda solución, existe un gran riesgo de no detectar ningún error si solo cambia el orden del identificador int "constantes". Con la primera solución, siempre notarás si estás usando el método en algunas clases olvidadas que de otra manera olvidarías modificar al nuevo identificador.
Si tiene un buen diseño, debería poder determinar si puede usar el enfoque de sobrecarga o si se encontrará con un problema donde si sobrecarga tendrá dos métodos con el mismo tipo de parámetro.
La sobrecarga parece ser la mejor manera al principio, pero si termina no pudiendo agregar un método en el futuro y arruinando las cosas con el nombramiento, va a ser una molestia.
Personalmente me gustaría para el enfoque de un nombre único por método, de esa manera no se encuentre con problemas más adelante al tratar de sobrecargar el mismo parámetro Métodos de objeto. Además, si alguien extendió su clase en el futuro e implementó otro void getEmployeeName (String name), no anularía el suyo.
Para resumir, vaya con un nombre de método único para cada método, la sobrecarga solo puede causar problemas a largo plazo.
Usaré nombres de métodos explícitos. Todos los que mantengan ese código y yo más tarde comprendan qué está haciendo ese método sin tener que escribir comentarios xml.
Utilizaría la primera opción, o la sobrecargaría en este caso, ya que tiene 4 firmas de parámetros diferentes. Sin embargo, ser específico ayuda a comprender el código dentro de 3 meses.
Yo elegiría el enfoque de "muchos". Me parece más intuitivo y menos propenso al error.
pegue todas sus opciones en una enumeración, tenga algo como lo siguiente
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
}
Estoy de acuerdo con Stephan: una tarea, un nombre de método , incluso si puedes hacerlo de varias maneras. La función de sobrecarga del método se proporcionó exactamente para su caso.
- getEmployeeName (int BatchID)
- getEmployeeName (cadena de correo electrónico)
- etc.
Y evite su segunda solución a toda costa. Huele a "tu antiguo vacío * de C". Del mismo modo, pasar un "Objeto" Java es casi tan pobre como un C "void *".
Estás pensando C / C ++.
Use objetos en lugar de un byte identificador (o int).
My Bad, el enfoque de sobrecarga es mejor y usar el SSN como clave principal no es tan bueno
public ??? getEmployeeName(Object obj){
if (obj instanceof Integer){
...
} else if (obj instanceof String){
...
} else if .... // and so on
} else throw SomeMeaningFullRuntimeException()
return employeeName
}
Creo que es mejor usar excepciones no marcadas para señalar una entrada incorrecta.
Documentarlo para que el cliente sepa qué objetos esperar. O crea tus propios envoltorios. Prefiero la primera opción.
Yo iría con Objetos de consulta . Funcionan bien para acceder a las tablas directamente. Si está confinado a procedimientos almacenados, pierde parte de su poder, pero aún puede hacerlo funcionar.
El primero es probablemente el mejor en Java, considerando que es seguro (a diferencia del otro). Además, para los tipos "normales", la segunda solución parece proporcionar un uso engorroso para el usuario. Sin embargo, dado que está utilizando Object como el tipo de SSN (que tiene un significado semántico más allá de Object), probablemente no se saldrá con ese tipo de API.
Con todo, en este caso particular, hubiera utilizado el enfoque con muchos captadores. Si todos los identificadores tienen su propio tipo de clase, podría haber ido por la segunda ruta, pero cambiando internamente en la clase en lugar de un identificador de tipo proporcionado / definido por la aplicación.