Pergunta
getEmployeeNameByBatchId(int batchID)
getEmployeeNameBySSN(Objecto SOCIAL)
getEmployeeNameByEmailId(String emailID)
getEmployeeNameBySalaryAccount(SalaryAccount salaryAccount)
ou
getEmployeeName(int typeOfIdentifier, byte[] identificador) -> nesta métodos o typeOfIdentifier diz se o identificador é batchID/SSN/emailID/salaryAccount
Uma dessas é a melhor maneira de implementar um método de obter?
Estes métodos seria em um Servlet e chamadas iria ser feita a partir de uma API que seria fornecido para os clientes.
Solução
Por que não sobrecarregar o getEmployeeName(??) método?
getEmployeeName(int BatchID)
getEmployeeName(objecto SOCIAL)(péssima idéia)
getEmployeeName(String Email)
etc.
Parece um bom 'muitos' abordagem para mim.
Outras dicas
Você pode usar algo como:
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));
}
Se você fazer a filtragem através de uma consulta SQL que você iria usar a Filter
interface para compor uma cláusula WHERE.
A grande vantagem desta abordagem é que você pode combinar dois filtros facilmente com:
public Filter and(final Filter f1,final Filter f2){
return new Filter(){
public boolean matches(Employee e) {
return f1.matches(e) && f2.matches(e);
}
};
}
e usá-lo assim:
findEmployee(and(byName("Gustav"),byBatchId(5)));
O que você recebe é semelhante ao Criteria
API do Hibernate.
Eu iria com o "muitos" abordagem.Parece mais intuitiva para mim, e menos propenso a erros.
Eu não gosto de getXByY() - que pode ser legal em PHP, mas eu só não gosto de Java (ymmv).
Eu iria com a sobrecarga, a menos que você tenha propriedades do mesmo tipo de dados.Nesse caso, eu gostaria de fazer algo semelhante para a sua segunda opção, mas em vez de usar ints, eu usaria um Enum para o tipo de segurança e clareza.E em vez de byte[], eu gostaria de usar o Objeto (por causa de autoboxing, isso também funciona para as primitivas).
Os métodos são o exemplo perfeito para o uso de sobrecarga.
getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)
Se os métodos comuns de processamento de dentro, basta escrever mais getEmplyeeNameImpl(...) e extrair lá o código comum para evitar a duplicação
Primeira opção, sem dúvida.Ser explícito.Ele vai lhe ajudar muito na manutenção e não há realmente nenhuma desvantagem.
@Stephan:é difícil para sobrecarregar um caso como este (em geral), porque os tipos de parâmetro não pode ser discriminatória, por exemplo,
- getEmployeeNameByBatchId(int batchId)
- getEmployeeNameByRoomNumber(int roomNumber)
Veja também os dois métodos getEmployeeNameBySSN, getEmployeeNameByEmailId na postagem original.
Vou usar o método explícito de nomes.A todos que mantém o código e a mim, mais tarde vai entender o que esse método está fazendo sem precisar escrever comentários xml.
Às vezes pode ser mais conveniant para usar o especificação padrão de.
Por exemplo:GetEmployee(ISpecification<Employee> especificação)
E, em seguida, começar a definir as suas especificações...
NameSpecification :ISpecification<Employee>
{
private string nome;
público NameSpecification(string nome) { isso.nome = nome;}
public bool IsSatisFiedBy(Funcionário funcionário) { return empregado.Nome == isso.nome;}
}
NameSpecification spec = new NameSpecification("Tim");
Funcionário da tim = MyService.GetEmployee(spec);
Gostaria de usar a primeira opção, ou sobrecarregá-lo, neste caso, de ver como você tem 4 parâmetros diferentes assinaturas.No entanto, ser específico ajuda a compreender o código de 3 meses a partir de agora.
É a lógica dentro de cada um desses métodos, basicamente, as mesmas?
Se assim for, o único método com parâmetro identificador pode fazer mais sentido (simples e redução de código repetido).
Se a lógica/procedimentos variam muito entre os tipos, um método, por tipo, pode ser o preferido.
Como outros sugeriram a primeira opção parece ser bom.O segundo pode fazer sentido quando você estiver escrevendo um código, mas quando alguém vem mais tarde, é mais difícil de descobrir como usar o código.( Eu sei, você tem comentários, e você pode sempre cavar fundo para o código, mas GetemployeeNameById é mais auto-explicativo)
Nota:Btw, o uso do Enum pode ser algo a considerar, em alguns casos.
Em um caso trivial como essa, gostaria de ir com a sobrecarga.O que é:
getEmployeeName( int batchID );
getEmployeeName( Object SSN );
etc.
Somente em casos especiais, eu iria especificar o tipo de argumento o nome do método, isto é,se o tipo de argumento é difícil determinar, se há vários tipos de argumentos tha tem o mesmo tipo de dados (batchId e employeeId, int), ou se a métodos para recuperar o empregado é radicalmente diferente para cada tipo de argumento.
Eu não posso ver por que eu sempre uso esse
getEmployeeName(int typeOfIdentifier, byte[] identifier)
como ele exige tanto de receptor e emissor de chamada para lançar o valor com base no typeOfIdentifier.Projeto ruim.
Se você reescrever a pergunta que você pode acabar se perguntando:
"SELECIONE o nome DO ..."
"SELECIONE SSN DE ..."
"SELECIONE e-mail DE ..."
vs.
"SELECT * FROM ..."
E eu acho que a resposta para isso é fácil e todo mundo sabe disso.
O que acontece se você alterar a classe do Funcionário?E. g.:Você tem que remover o e-mail e adicionar um novo filtro, como departamento.Com a segunda solução, você tem um grande risco de não perceber erros, se você quiser apenas alterar a ordem dos int identificador de "constantes".Com a primeira solução que você sempre vai notar se você estiver usando o método, em algum tempo esquecido classes, de alguma forma você se esqueça de modificar para o novo identificador.
Eu, pessoalmente, prefiro ter o explícito de nomeação "...ByRoomNumber", porque, se você acabar com muitos "sobrecargas" você vai, eventualmente, introduzir erros indesejados.Sendo explícito é imho o melhor caminho.
Concordo com Stephan:Uma tarefa, um nome de método, mesmo se você pode fazê-lo de várias maneiras.A sobrecarga de método recurso foi fornecida exatamente para o seu caso.
- getEmployeeName(int BatchID)
- getEmployeeName(String Email)
- etc.
E evitar a segunda solução a todo o custo.Ele cheira "a tua olde void * de C".Da mesma forma, a passagem de um Java "Objeto" é quase tão ruim que o estilo de um C "void *".
Se você tem um bom design, você deve ser capaz de determinar se você pode usar a sobrecarga de abordagem ou se você está indo para executar um problema onde se sobrepor você vai acabar tendo dois métodos com o mesmo tipo de parâmetro.
A sobrecarga parece ser a melhor maneira inicialmente, mas se você acabar por não ser capaz de adicionar um método no futuro e bagunçar as coisas com nomenclatura que vai ser uma trabalheira.
Pessoalmente, eu iria para a abordagem de um único nome, por método, dessa forma, você não ter problemas mais tarde com a tentativa de sobrepor-se o mesmo parâmetro métodos do Objeto.Também, se alguém estendido sua classe no futuro e implementadas outro vazio getEmployeeName(String nome) ele não iria substituir o seu.
Para resumir, vá com um método único nome para cada método, a sobrecarga pode causar problemas a longo prazo.
A dissociação entre o processo de pesquisa e os critérios de pesquisa jrudolf propõe, no seu exemplo é excelente.Eu me pergunto por que não é o mais votado solução.Posso perder alguma coisa?
Eu iria com Objetos De Consulta.Eles funcionam bem para aceder a tabelas diretamente.Se você está confinado procedimentos armazenados, elas perdem um pouco de sua força, mas você ainda pode fazê-lo funcionar.
O primeiro é, provavelmente, o melhor em Java, considerando que se trata typesafe (ao contrário dos outros).Além disso, para "normal" tipos", a segunda solução parece apenas fornecer complicado de uso para o usuário.No entanto, desde que você está usando o Objeto como o tipo de SSN (que tem um significado semântico, além de Objeto), você provavelmente não vai sair com esse tipo de API.
Tudo-em-tudo, neste caso particular, eu teria usado a abordagem com muitas getters.Se todos os identificadores têm a sua própria classe, tipo, eu poderia ter ido para o segundo percurso, mas a mudança internamente na classe em vez de um ou de aplicação definido pelo tipo de identificador.
vara de todas as suas opções em um enum, a ter algo como o seguinte
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
}
Você está pensando em C/C++.
Use os objetos em vez de um identificador de byte (ou int).
My Bad, a sobrecarga de abordagem é melhor e utilizar o CPF como chave primária não é tão bom
public ??? getEmployeeName(Object obj){
if (obj instanceof Integer){
...
} else if (obj instanceof String){
...
} else if .... // and so on
} else throw SomeMeaningFullRuntimeException()
return employeeName
}
Eu acho que é melhor usar Exceções não verificadas para sinalização de entrada incorreta.
Documento-lo para que o cliente saiba quais objetos para esperar.Ou criar seus próprios invólucros.Eu prefiro a primeira opção.