Essa pergunta é subjetiva, mas fiquei curioso em saber como a maioria dos programadores aborda isso. O exemplo abaixo está em pseudo-C #, mas isso também deve se aplicar a Java, C ++ e outras linguagens OOP.
De qualquer forma, ao escrever métodos auxiliares em minhas classes, eu os declaro estáticos e apenas passo os campos se o método auxiliar precisar deles. Por exemplo, dado o código abaixo, prefiro usar a Chamada de Método # 2 .
class Foo
{
Bar _bar;
public void DoSomethingWithBar()
{
// Method Call #1.
DoSomethingWithBarImpl();
// Method Call #2.
DoSomethingWithBarImpl(_bar);
}
private void DoSomethingWithBarImpl()
{
_bar.DoSomething();
}
private static void DoSomethingWithBarImpl(Bar bar)
{
bar.DoSomething();
}
}
Minha razão para fazer isso é que deixa claro (pelo menos aos meus olhos) que o método auxiliar tem um possível efeito colateral em outros objetos - mesmo sem ler sua implementação. Eu acho que posso rapidamente entender métodos que usam essa prática e, assim, me ajudam a depurar as coisas.
O que você prefere fazer em seu próprio código e quais são seus motivos?
Respostas:
Isso realmente depende. Se os valores em que seus ajudantes operam são primitivos, os métodos estáticos são uma boa opção, como Péter apontou.
Se eles são complexos e, em seguida SÓLIDO aplica-se, mais especificamente, o S , o eu e o D .
Exemplo:
Isso seria sobre o seu problema. Você pode criar
makeEveryBodyAsHappyAsPossible
um método estático, que terá os parâmetros necessários. Outra opção é:Agora
OurHouse
não é necessário conhecer os meandros das regras de distribuição de cookies. Agora, ele deve apenas um objeto que implemente uma regra. A implementação é abstraída para um objeto, cuja única responsabilidade é aplicar a regra. Este objeto pode ser testado isoladamente.OurHouse
pode ser testado usando um mero mock doCookieDistributor
. E você pode facilmente decidir alterar as regras de distribuição de cookies.No entanto, tome cuidado para não exagerar. Por exemplo, ter um sistema complexo de 30 classes age como a implementação de
CookieDistributor
, onde cada classe apenas cumpre uma tarefa minúscula, realmente não faz sentido. Minha interpretação do SRP é que ele não apenas determina que cada classe possa ter apenas uma responsabilidade, mas também que uma única responsabilidade deve ser realizada por uma única classe.No caso de primitivas ou objetos que você usa como primitivas (por exemplo, objetos representando pontos no espaço, matrizes ou algo assim), as classes auxiliares estáticas fazem muito sentido. Se você tem a opção, e isso realmente faz sentido, você pode realmente considerar adicionar um método à classe que representa os dados, por exemplo, é sensato que um
Point
tenha umadd
método. Novamente, não exagere.Portanto, dependendo do seu problema, existem diferentes maneiras de solucioná-lo.
fonte
É um idioma bem conhecido declarar métodos de classes de utilidade
static
; portanto, essas classes nunca precisam ser instanciadas. Seguir esse idioma facilita a compreensão do seu código, o que é uma coisa boa.Porém, existe uma séria limitação a essa abordagem: esses métodos / classes não podem ser facilmente zombados (embora o AFAIK, pelo menos para C #, exista estruturas de zombaria que podem alcançar isso, mas elas não são comuns e pelo menos algumas são comercial). Portanto, se um método auxiliar tiver alguma dependência externa (por exemplo, um banco de dados), o que dificulta o teste de unidade - assim seus chamadores -, é melhor declará-lo não estático . Isso permite a injeção de dependência, facilitando assim os chamadores do método ao teste de unidade.
Atualizar
Esclarecimento: o acima fala sobre classes de utilidade, que contêm apenas métodos auxiliares de baixo nível e (normalmente) nenhum estado. Os métodos auxiliares nas classes não utilitárias com estado são um problema diferente; desculpas por interpretar mal o OP.
Nesse caso, sinto um cheiro de código: um método da classe A que opera principalmente em uma instância da classe B pode realmente ter um lugar melhor na classe B. Mas se eu decidir mantê-lo onde está, prefiro a opção 1, como é mais simples e mais fácil de ler.
fonte
Prefiro o número 1 (
this->DoSomethingWithBarImpl();
), a menos que o método auxiliar não precise acessar os dados / implementação da instânciastatic t_image OpenDefaultImage()
.interface pública e implementação privada e membros são separados. os programas seriam muito mais difíceis de ler se eu optasse pelo segundo. com # 1, eu sempre tenho os membros e a instância disponíveis. comparado a muitas implementações baseadas em OO, eu costumo usar muito encapsualtion e muito poucos membros por classe. no que diz respeito aos efeitos colaterais - eu estou bem com isso, geralmente há validação de estado que amplia as dependências (por exemplo, argumentos que seria necessário passar).
O número 1 é muito mais simples de ler, manter e possui boas características de desempenho. é claro, haverá casos em que você poderá compartilhar uma implementação:
Se o nº 2 fosse uma boa solução comum (por exemplo, o padrão) em uma base de código, eu ficaria preocupado com a estrutura do design: as classes estão fazendo muito? não há encapsulamento suficiente ou reutilização suficiente? o nível de abstração é alto o suficiente?
por fim, o número 2 parece redundante se você estiver usando linguagens OO nas quais a mutação é suportada (por exemplo, um
const
método).fonte