Classes de utilidade são más?

Eu vi esse fio

Se uma class “Utilities” é ruim, onde coloco meu código genérico?

e pensei por que as classs de utilidade são más?

Digamos que eu tenha um modelo de domínio com dezenas de classs de profundidade. Eu preciso ser capaz de instâncias xml-ify. Eu faço um método toXml no pai? Eu faço uma class auxiliar MyDomainXmlUtility.toXml? Este é um caso em que a necessidade de negócios abrange todo o modelo de domínio – ele realmente pertence a um método de instância? E se houver um monte de methods auxiliares na funcionalidade xml do aplicativo?

As classs de utilitários não são exatamente más, mas podem violar os princípios que compõem um bom projeto orientado a objects. Em um bom design orientado a object, a maioria das classs deve representar uma única coisa e todos os seus atributos e operações. Se você estiver operando em uma coisa, esse método provavelmente deve ser um membro dessa coisa.

No entanto, há momentos em que você pode usar classs de utilitário para agrupar vários methods juntos – um exemplo é a class java.util.Collections que fornece vários utilitários que podem ser usados ​​em qualquer Coleção Java. Eles não são específicos de um tipo específico de Coleção, mas implementam algoritmos que podem ser usados ​​em qualquer Coleção.

Realmente, o que você precisa fazer é pensar em seu design e determinar onde faz mais sentido colocar os methods. Normalmente, é como operações dentro de uma class. No entanto, às vezes, é de fato como uma class de utilitário. Quando você usa uma class de utilitário, no entanto, não apenas lance methods randoms, ao invés disso, organize os methods por finalidade e funcionalidade.

Eu acho que o consenso geral é que as classs de utilidade não são perversas. Você só precisa usá-los criteriosamente:

  • Projete os methods de utilitário estáticos para serem gerais e reutilizáveis. Certifique-se de que eles são apátridas; ou seja, sem variables ​​estáticas.

  • Se você tiver muitos methods de utilitário, particione-os em classs de uma maneira que facilite para os desenvolvedores encontrá-los.

  • Não use classs de utilitário em que methods estáticos ou de instância em uma class de domínio seriam uma solução melhor. Por exemplo, considere se os methods em uma class base abstrata ou em uma class auxiliar instanciada seriam uma solução melhor.

  • Para o Java 8 em diante, os “methods padrão” em uma interface podem ser uma opção melhor que as classs de utilitários.


A outra maneira de olhar para esta questão é observar que na pergunta citada, “Se as classs de utilidade são” malignas “” é um argumento do tipo palha”. É como eu perguntando:

“Se os porcos podem voar, devo carregar um guarda-chuva?”

Na pergunta acima, eu não estou realmente dizendo que os porcos podem voar … ou que eu concordo com a proposição de que eles poderiam voar.

Típico “xyz é mal” declarações são dispositivos retóricos que se destinam a fazer você pensar, colocando um ponto de vista extremo. Eles são raramente (ou nunca) destinados a declarações de fatos literais.

As classs de utilitários são problemáticas porque não agrupam responsabilidades com os dados que as suportam.

No entanto, eles são extremamente úteis e eu os construo o tempo todo como estruturas permanentes ou como degraus durante um refator mais completo.

De uma perspectiva de Código Limpo , as classs de utilidade violam a Responsabilidade Única e o Princípio Aberto-Fechado. Eles têm muitas razões para mudar e são, por design, não extensíveis. Eles realmente deveriam existir apenas durante a refatoração como um intermediário.

Eu suponho que começa a se tornar mal quando

1) Ele fica muito grande (apenas agrupe-os em categorias significativas nesse caso).
2) Métodos que não devem ser methods estáticos estão presentes

Mas, desde que essas condições não sejam cumpridas, acho que são muito úteis.

Classes de utilidade são ruins porque significam que você estava com preguiça de achar um nome melhor para a class 🙂

Dito isto, eu sou preguiçoso. Às vezes você só precisa fazer o trabalho e sua mente fica em branco. É quando as classs “Utility” começam a se infiltrar.

É muito fácil marcar algo como uma utilidade simplesmente porque o designer não conseguia pensar em um local apropriado para colocar o código. Muitas vezes existem poucos “utilitários” verdadeiros.

Como regra geral, eu normalmente mantenho o código no pacote onde ele é usado pela primeira vez, e só refojo para um lugar mais genérico se eu achar que depois ele é realmente necessário em outro lugar. A única exceção é se eu já tiver um pacote que executa uma funcionalidade semelhante / relacionada, e o código se encheckbox melhor nele.

Eu não concordo inteiramente que as classs de utilidade são más.

Enquanto uma class de utilitários pode violar os diretores de OO de algumas maneiras, eles nem sempre são ruins.

Por exemplo, imagine que você deseje uma function que limpe uma string de todas as substrings que correspondam ao valor x.

stl c ++ (a partir de agora) não suporta diretamente isso.

Você pode criar uma extensão polimórfica de std :: string.

Mas o problema é, você realmente quer que todas as strings que você usa em seu projeto sejam a sua class de strings extendida?

Há momentos em que OO realmente não faz sentido, e este é um deles. Queremos que o nosso programa seja compatível com outros programas, então vamos ficar com std :: string e criar uma class StringUtil_ (ou algo assim).

Eu diria que é melhor se você ficar com um utilitário por class. Eu diria que é bobagem ter um util para todas as classs ou muitos utilitários para uma class.

Classes de utilitários contendo methods estáticos sem estado podem ser úteis. Geralmente, são muito fáceis de testar na unidade.

Com o Java 8 você pode usar methods estáticos em interfaces … problema resolvido.

Olhando para essa questão agora, eu diria que os methods de extensão C # destroem completamente a necessidade de classs de utilitários. Mas nem todas as línguas têm uma construção tão genérica.

Você também tem JavaScript, onde você pode simplesmente adicionar uma nova function ao object existente.

Mas não tenho certeza se realmente existe uma maneira elegante de resolver este problema em uma linguagem mais antiga como o C ++ …

Um bom código OO é meio difícil de escrever, e é difícil de encontrar já que escrever Good OO requer muito mais tempo / conhecimento do que escrever código funcional decente.

E quando você está em um orçamento, seu chefe nem sempre fica feliz em ver que você passou o dia inteiro escrevendo um monte de aulas …

A maioria das classs util são ruins porque:

  1. Eles ampliam o escopo dos methods. Eles tornam o código público que, de outra forma, seria privado. Se o método util é estável (ou seja, não precisa de atualização) é melhor, na minha opinião, copiar e colar methods auxiliares privados do que expô-lo como API e tornar mais difícil entender o que é o ponto de input público para um componente manter uma tree estruturada chamada hierarquia com um pai por método que é mais fácil segregar mentalmente em componentes, o que é mais difícil quando você tem methods chamados a partir de vários methods pais).
  2. Eles resultam em código morto. Os methods util ao longo do tempo tornam-se não utilizados à medida que seu aplicativo evolui e você acaba com o código não utilizado poluindo sua base de código. Se ele permanecesse privado, seu compilador diria que o método não é usado e você poderia simplesmente removê-lo (o melhor código é nenhum código).

Existem algumas analogias para bibliotecas estáticas versus dinâmicas.

Regra de ouro

Você pode ver este problema de duas outlook:

  • Geral *Util methods *Util são frequentemente uma sugestão de design de código incorreto ou convenção de nomes preguiçosos.
  • É uma solução de design legítimo para funcionalidades sem estado reutilizáveis ​​de domínio cruzado. Por favor, note que para quase todos os problemas comuns existem soluções existentes.

Exemplo 1. Corrigir o uso de classs / módulos de util . Exemplo de biblioteca externa

Vamos supor que você está escrevendo aplicativo que gerencia empréstimos e cartões de crédito. Os dados desses módulos são expostos por meio de serviços da Web no formato json . Em teoria, você pode converter manualmente objects em strings que estarão no json , mas isso reinventaria a roda. A solução correta seria include nos dois módulos biblioteca externa usada para converter objects java no formato desejado. (na imagem de exemplo eu mostrei gson )

insira a descrição da imagem aqui


Exemplo 2. Uso correto de classs / módulos de util . Escrevendo seu próprio util sem desculpas para outros membros da equipe

Como caso de uso, presumimos que precisamos realizar alguns cálculos em dois módulos de aplicação, mas ambos precisam saber quando há feriados públicos na Polônia. Em teoria, você pode fazer esses cálculos dentro de módulos, mas seria melhor extrair essa funcionalidade para separar o módulo.

Aqui está um detalhe pequeno, mas importante. Classe / módulo que você escreveu não é chamado HolidayUtil , mas PolishHolidayCalculator . Funcionalmente, é uma class util , mas conseguimos evitar a palavra genérica.

insira a descrição da imagem aqui

Classes de utilidade nem sempre são más. Mas eles devem conter apenas os methods comuns em uma ampla gama de funcionalidades. Se houver methods que só possam ser usados ​​em um número limitado de classs, considere criar uma class abstrata como pai comum e coloque os methods nela.

Quando eu não posso adicionar um método a uma class (digamos, a Account é bloqueada contra alterações por desenvolvedores Jr.), eu apenas adiciono alguns methods estáticos à minha class Utilities da seguinte forma:

 public static int method01_Account(Object o, String... args) { Account acc = (Account)o; ... return acc.getInt(); } 
Intereting Posts