A maneira mais amigável para o homem de solicitar definições de métodos de classe?

38

Em qualquer definição de classe, vi as definições de método ordenadas de várias maneiras: alfabética, cronológica com base no uso mais comum, alfabética agrupada por visibilidade, alfabética com getters e setters agrupados etc. Quando eu começo a escrever uma nova classe, Costumo digitar tudo e depois reordenar quando terminar de escrever a turma inteira. Nessa nota, tenho três perguntas:

  1. A ordem importa?
  2. Existe uma "melhor" ordem?
  3. Suponho que não, então quais são os prós e os contras das diferentes estratégias de pedidos?
Johntron
fonte
11
Você realmente não espera que as pessoas recortem / colem código simplesmente para reordenar métodos. Se o IDE fizer isso automaticamente, tudo bem. Caso contrário, é difícil de aplicar.
Reactgular
Para esclarecer, minha pergunta é sobre legibilidade / usabilidade, não sintaxe.
Johntron
11
Relacionados: programmers.stackexchange.com/questions/186418/...
Anthony Pegram

Respostas:

52

Em algumas linguagens de programação, a ordem importa porque você não pode utilizar as coisas até que elas tenham sido declaradas. Mas, exceto para a maioria dos idiomas, isso não importa para o compilador. Então, você fica com isso importando para os humanos.

Minha citação favorita de Martin Fowler é: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.Então, eu diria que a ordem de sua classe deve depender do que facilita a compreensão pelos seres humanos.

Pessoalmente, prefiro o tratamento que Bob Martin dá em seu Clean Codelivro. Variáveis ​​de membro na parte superior da classe, construtores e todos os outros métodos. E você ordena que os métodos sejam próximos da maneira como são usados ​​na classe (em vez de colocar arbitrariamente todo público, depois privado e depois protegido). Ele chama isso de minimizar a "distância vertical" ou algo assim (não tenho o livro comigo no momento).

Editar:

A idéia básica da "distância vertical" é que você deseja evitar que as pessoas pulem ao redor do seu código-fonte apenas para entendê-lo. Se as coisas estiverem relacionadas, elas devem estar mais próximas. Coisas não relacionadas podem estar mais afastadas.

O Capítulo 5 do Código Limpo (ótimo livro, btw) entra em vários detalhes sobre como o Sr. Martin sugere o pedido de código. Ele sugere que a leitura do código funcione como a leitura de um artigo de jornal: os detalhes de alto nível vêm primeiro (na parte superior) e você obtém mais detalhes à medida que lê. Ele diz: "Se uma função chama outra, elas devem estar verticalmente próximas e o chamador deve estar acima do chamado, se possível". Além disso, os conceitos relacionados devem estar próximos.

Então, aqui está um exemplo artificial que é ruim de várias maneiras (design pobre de OO; nunca use doublepor dinheiro), mas ilustra a idéia:

public class Employee {
  ...
  public String getEmployeeId() { return employeeId; }
  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }

  public double calculatePaycheck() {
    double pay = getSalary() / PAY_PERIODS_PER_YEAR;
    if (isEligibleForBonus()) {
      pay += calculateBonus();
    }
    return pay;
  }

  private double getSalary() { ... }

  private boolean isEligibleForBonus() {
    return (isFullTimeEmployee() && didCompleteBonusObjectives());
  }

  public boolean isFullTimeEmployee() { ... }
  private boolean didCompleteBonusObjectives() { ... }
  private double calculateBonus() { ... }
}

Os métodos são ordenados para que sejam próximos aos que os chamam, descendo de cima para baixo. Se tivéssemos colocado todos os privatemétodos abaixo publicdesses, você teria que fazer mais pulos para seguir o fluxo do programa.

getFirstNamee getLastNamesão conceitualmente relacionados (e getEmployeeIdprovavelmente também), por isso estão próximos. Poderíamos movê-los todos para o fundo, mas não gostaríamos de ver de getFirstNamecima e de getLastNamebaixo.

Espero que isso lhe dê a idéia básica. Se você está interessado nesse tipo de coisa, recomendo fortemente a leitura Clean Code.

Allan
fonte
Eu preciso saber como setters e getters de variáveis ​​de instância precisam ser colocados. Deve vir logo após o construtor da classe ou na parte inferior da classe?
srinivas
Pessoalmente, gosto deles no topo, depois do construtor. Mas isso realmente não importa; Eu recomendaria consistência no seu projeto e com sua equipe como uma boa maneira de decidir.
Allan
Não deveria calculateBonus()vir antes isFullTimeEmployee()e didCompleteBonusObjectives()?
winklerrr
@winklerrr Eu posso ver um argumento para isso. I colocou onde fiz porque isFullTimeEmployeee didCompleteBonusObjectivessão usados por isEligibleForBonusforma que deveria ser verticalmente perto dele. Mas você pode se mover calculateBonuspara aproximar-se de onde é chamado. Infelizmente, como você tem funções que chamam funções, você acaba com problemas (como uma função compartilhada chamada por várias outras) em que não há uma ordem perfeita. Então fica a seu critério. Eu recomendo manter classes e funções pequenas para atenuar esses problemas.
Allan
2

Geralmente, ordeno meus métodos por relação e ordem de uso.

Faça uma aula de rede, eu vou agrupar todos os métodos TCP juntos, depois todos os métodos UDP. No TCP interno, eu teria o método de instalação como o primeiro, talvez envie uma determinada mensagem em segundo e feche o soquete TCP como terceiro.

Obviamente, nem todas as classes se encaixam nesse padrão, mas esse é o meu fluxo de trabalho geral.

Faço isso dessa maneira para depurar mais do que qualquer outra coisa, quando tenho um problema e quero pular para o método, não penso como está escrito, acho o que é responsável e vou para essa seção.

Dessa forma, em particular, faz sentido para terceiros visualizar / usar seu código como agrupado e seguirá a ordem em que está sendo usado; portanto, o código que eles escreverão com sua classe seguirá a mesma estrutura que a classe.

No que diz respeito isso importa?

para legibilidade, definitivamente.

diferente disso não, apenas nos casos em que determinados idiomas você não pode chamar o método, a menos que seja definido acima onde é chamado etc.

Simon McLoughlin
fonte
0

Idealmente, suas aulas são tão pequenas que não importam. Se você possui apenas uma dúzia de métodos e seu editor ou IDE suporta dobragem, não há problema, porque a lista inteira de métodos se encaixa em 12 linhas.

Caso contrário, a distinção de nível superior deve ser pública versus privada. Liste os métodos públicos primeiro: estes são o que as pessoas mais procurarão, porque definem a maneira como sua classe interage com o restante da base de código.

Então, dentro de cada uma delas, faz mais sentido agrupar métodos por funcionalidade: construtores e destruidores em um bloco, getters / setters em outro, sobrecargas de operadores, métodos estáticos e o resto do grupo. No C ++, eu gosto de me manter operator=próximo dos construtores, porque está intimamente relacionado ao construtor de cópias e também porque quero poder identificar rapidamente se todos (ou nenhum) do padrão ctor, copy ctor, operator = e dtor existir.

tdammers
fonte
-1

tl; dr

Somente se o idioma em que você estiver trabalhando exigir uma ordem específica. Fora isso, a encomenda é sua. Escolha um sistema que seja consistente e faça sentido e tente segui-lo o máximo possível.


1 A ordem importa?

Somente se o idioma em que você estiver trabalhando precisar ter uma função definida anteriormente no arquivo, onde não é chamada, como neste exemplo:

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

você receberá um erro porque telefonou funcB()antes de usá-lo. Eu acho que esse é um problema no PL / SQL e possivelmente também no C, mas você pode ter declarações avançadas como:

void funcB();

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

Essa é a única situação em que consigo pensar onde, se a ordem estiver "errada", você nem será capaz de compilar.

Caso contrário, você sempre poderá reordená-los da maneira que desejar. Você provavelmente poderia até escrever uma ferramenta para fazer isso por você (se não conseguir encontrar uma por aí).

2) Existe uma "melhor" ordem?

Se o idioma / ambiente não tiver requisitos para pedidos, o "melhor" é o que melhor funciona para você . Para mim, eu gosto de ter todos os getters / setters juntos, geralmente no início da classe (mas depois de construtores / inicializadores estáticos) e, em seguida, os métodos private, depois protegidos e depois públicos. Em cada grupo com base no escopo, geralmente não há pedidos, embora os métodos sobrecarregados que eu tento manter juntos, na ordem do número de parâmetros. Também tento manter métodos com funcionalidade relacionada juntos, embora às vezes precise interromper minha ordem com base no escopo; e, às vezes, tentar manter a ordem com base no escopo interrompe o grupo por funcionalidade. E meu IDE pode me fornecer uma visualização de estrutura de tópicos alfabética, o que também é bom. ;)

Alguns idiomas, como o C #, têm a capacidade de agrupar códigos em "regiões" que não têm efeito na compilação, mas podem facilitar a manutenção de funções relacionadas e, em seguida, ocultar / exibi-las com o IDE. Como MainMa apontou , há quem considere isso uma má prática. Vi bons e maus exemplos de regiões sendo usadas dessa maneira; portanto, se você for por esse caminho, tenha cuidado.

FrustratedWithFormsDesigner
fonte