O que é um código de "inveja de recursos" e por que é considerado um cheiro de código?

53

Esta pergunta sobre o SO fala sobre a correção do que o OP pensava ser um código de inveja de recursos . Outro exemplo em que vi essa frase bacana sendo citada está em uma resposta recentemente dada aqui em programmers.SE. Embora eu tenha deixado um comentário a essa resposta solicitando as informações, pensei que seria de grande ajuda para os programadores que seguem as perguntas e respostas entender o que significa o termo inveja de recursos . Sinta-se à vontade para editar tags adicionais, se achar apropriado.

Nerd
fonte

Respostas:

88

Inveja de recurso é um termo usado para descrever uma situação em que um objeto chega aos campos de outro objeto para executar algum tipo de cálculo ou tomar uma decisão, em vez de solicitar ao objeto que faça o próprio cálculo.

Como um exemplo trivial, considere uma classe representando um retângulo. O usuário do retângulo pode precisar conhecer sua área. O programador pode expor widthe heightcampos e, em seguida, fazer o cálculo fora da Rectangleclasse. Alternativamente, Rectanglepoderia manter o widthe heightcampos privados e fornecer um getAreamétodo. Esta é sem dúvida uma abordagem melhor.

O problema com a primeira situação e o motivo pelo qual é considerado um cheiro de código é porque ele quebra o encapsulamento.

Como regra geral, sempre que você fizer uso extensivo de campos de outra classe para executar qualquer tipo de lógica ou computação, considere mover essa lógica para um método na própria classe.

jhewlett
fonte
7
+1, embora seu exemplo não seja realista, pois uma classe Rectangle útil normalmente expõe os campos de largura e altura.
Doc Brown
2
E embora a quebra do encapsulamento possa ocorrer junto com o "ambiente de recursos", na maioria dos exemplos do mundo real que eu vi até agora, provavelmente não foi o caso. Isso acontece mais em situações "ei, eu preciso calcular algumas coisas apenas no código usando esse objeto, e não tenho certeza se posso tocar na implementação desse objeto / se devemos atribuir ao objeto a responsabilidade por esse cálculo". E então implementamos o cálculo usando campos que já estão expostos (embora uma implementação muito mais limpa provavelmente seja possível dentro do objeto).
Doc Brown
2
@DocBrown Imagine um retângulo desenhado na superfície de um toro, cone ou esfera. Se minha biblioteca de desenho de formas produz objetos capazes de produzir os resultados corretos em tais contextos, você seria tolo em não deixá-los calcular suas próprias áreas - em qualquer contexto.
itsbruce
11
@OskarN .: Por definição, estamos falando de funções que são necessárias. Elas são obviamente necessárias se outras classes as reimplementarem repetidamente.
Aaronaught 24/09
11
@OskarN .: depende; às vezes a decisão é clara, às vezes é uma questão de gosto e, na maioria das vezes, é uma questão de experiência. No seu artigo, há boas razões pelas quais Scott Meyers escreve " às vezes menos é mais" e levou anos para entender quando não aplicar seu "algoritmo para decidir quando fazer com que um membro funcione".
Doc Brown
1

Existe uma situação possível quando não há problema em usar outros métodos de classe / estrutura extensivamente - quando sua classe / estrutura é um contêiner para dados. Geralmente há um pouco que você pode fazer com esses dados sem contexto externo.

Essas classes ainda podem conter alguma lógica interna, mas mais frequentemente são usadas como contêineres:

class YourUid {
 public:
  YourUid(int id_in_workplace_, int id_in_living_place_, DB* FBI_database, int id_in_FBI_database);
  bool IsInvalidWorker() const { return id_in_workplace == consts::invalid_id_in_workplace; }
  bool CanMessWith() const { return !FBI_database_.is_cool(id_in_FBI_database_); }
  int id_in_workplace;
  int id_in_living_place;
 private:
  int id_in_FBI_database_;
  const DB* FBI_database_;
};

@jhewlett em sua resposta se refere a este artigo para provar que você não deve usar outros membros da classe extensivamente, mas há outra situação de cheiros de código descrita lá com advogados no meu exemplo:

Lista longa de parâmetros. Limite o número de parâmetros necessários em um determinado método ou use um objeto para combinar os parâmetros.

Riga
fonte
11
Como isso responde à pergunta?
mosquito
@gnat O Q é sobre Por que é considerado "cheiro de código". jhewlett dá um A com algumas suposições gerais demais questionadas nos comentários. Minha resposta é 2 centavos para distinguir "cheiro de código" da prática normal.
Riga