É um cheiro de código se você está criando frequentemente um objeto apenas para chamar um método nele

14

Eu herdei uma base de código onde há muito código que é mais ou menos assim:

SomeDataAdapter sda = new SomeDataAdapter();
sda.UpdateData(DataTable updateData);

E então sda nunca é usado novamente.

Isso é um cheiro de código que indica que esses métodos devem realmente ser métodos de classe estática?

Shane Wealti
fonte
Essas classes implementam interfaces?
Reactgular 19/03/19
7
O dia seguinte à refatoração dos métodos estáticos será o dia em que você deseja executar testes de unidade com uma versão simulada do seu adaptador de dados.
1955 Mike
22
@ Mike: Por que você precisaria zombar de um método estático? Estou ficando muito cansado desse argumento falacioso de que métodos estáticos não são testáveis. Se seus métodos estáticos estão mantendo o estado ou criando efeitos colaterais, a culpa é sua , não da sua metodologia de teste.
Robert Harvey
9
Na minha opinião, é um cheiro de linguagem mostrando a fraqueza da análise "tudo deve ser uma classe".
Ben
7
@RobertHarvey: pode ser necessário zombar de um método estático pelo mesmo motivo que zomba de qualquer outro método: é muito caro ligar durante o teste de unidade.
precisa

Respostas:

1

Eu consideraria um cheiro de arquitetura em que UpdateData provavelmente deveria pertencer a uma classe 'service'.

Onde os dados são uma Apple. Onde AppleAdapter é a classe de serviço / business intelligence. Onde AppleService é uma referência Singleton a um AppleAdapter que existe fora do método atual.

private static volatile AppleAdapter _appleService = null;
private static object _appleServiceLock = new object();
private AppleAdapter AppleService
{
    get
    {
        if (_appleService == null)
        {
            lock (_appleServiceLock)
            {
                if (_appleService == null)
                    _appleService = new AppleAdapter();
            }
        }
        return _appleService;
    }
}

public SomeAppleRelatedMethod(Apple apple)
{
    AppleService.UpdateData(apple);
}

Eu não acho que o que você está fazendo esteja errado necessariamente, mas se SomeDataAdapter realmente representar algum tipo de serviço de negócios sem estado, um singleton seria a melhor prática para ele. Espero que ajude! O exemplo fornecido é uma maneira sofisticada de garantir nenhuma contenção do _appleService se ele for nulo e acessado exatamente ao mesmo tempo por dois ou mais encadeamentos.

Você sabe o que? Se SomeDataAdapter for um ADO IDbDataAdapter (o que quase certamente é), desconsidere toda a resposta!

: P

Não tenho permissão para adicionar um comentário à pergunta original, mas se você puder especificar onde esse código existe.

Se esse código representa uma implementação personalizada de um IDbDataAdapter, e o UpdateData está criando um IDbConnection, IDbCommand e conectando tudo nos bastidores, então não, eu não consideraria um cheiro de código, porque agora estamos falando de fluxos e outros coisas que precisam ser descartadas quando terminarmos de usá-las.

Andrew Hoffman
fonte
12
Socorro! Estou me afogando em padrões de software.
Robert Harvey
4
... ou injetado como uma dependência. ;)
Rob
12
Brincar com singletons e travamento duplo para obter algo equivalente a uma função / procedimento simples é um cheiro muito maior para mim!
21914 Ben
3

Eu acho que esse problema é ainda mais profundo do que isso. Mesmo se você o refatorar para um método estático, obterá o código onde você chama o método estático único em todo o lugar. Que na minha opinião é o cheiro do código em si. Pode indicar que está faltando alguma abstração importante. Talvez você queira criar um código que faça algum pré e pós-processamento, permitindo alterar o que acontece no meio. Esse pré e pós-processamento conterão as chamadas comuns, enquanto o intervalo dependerá da implementação concreta.

Eufórico
fonte
Concordo que há um problema muito mais profundo. Estou tentando aprimorá-lo gradualmente sem uma reformulação completa da arquitetura, mas parece que o que eu estava pensando não é uma boa maneira de fazê-lo.
Shane Wealti 19/03/14
1

Mais ou menos. Isso geralmente significa que você deseja distribuir uma função e seu idioma de escolha não permite. É meio desajeitado e deselegante, mas se você está preso em um idioma sem funções de primeira classe, não há muito o que fazer.

Se nenhum desses objetos estiver sendo passado como argumento para outras funções, você poderá transformá-los em métodos estáticos e nada mudará.

Doval
fonte
Também pode significar que você deseja que o método estático retorne uma versão modificada (ou uma cópia modificada) de um objeto que você está passando para ele.
Robert Harvey
2
"se você estiver preso em um idioma sem funções de primeira classe": não há diferença entre um objeto com apenas um método e uma função de primeira classe (ou fechamento de primeira classe): são apenas duas visões diferentes da mesma coisa.
Giorgio
4
@Giorgio Teoricamente, não. Na prática, se o seu idioma não tiver pelo menos um açúcar de sintaxe, é a diferença entre fn x => x + 1e new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }};ou se limitar a algumas funções codificadas e de pouca utilidade.
Doval
Por que não poderia fn x => x + 1ser o açúcar sintático new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }}? Ok, talvez você queira dizer se alguém está preso em um idioma sem esse tipo de açúcar sintático.
Giorgio
@Giorgio Você terá que perguntar à Oracle. (É verdade que isso está mudando com o Java 8). Observe que você precisaria de mais açúcar de sintaxe do que apenas isso para ser realmente útil - também desejaria passar métodos pré-declarados por nome. Curry também seria útil. Em algum momento, você deve se perguntar se vale a pena ter todos esses hacks em vez de tratar as funções como primeiros cidadãos. Mas agora estou ficando fora de tópico.
Doval
0

Se o estado de posse torna uma determinada classe mais utilitária, funcional ... reutilizável, então não. Por alguma razão, o padrão de design de comando vem à mente; esse motivo certamente não é o desejo de afogar Robert Harvey.

radarbob
fonte
0

Defina "frequentemente". Com que frequência você instancia o objeto? Muito - provavelmente não?

É provável que haja problemas maiores no seu sistema. Ficar estático comunicará mais claramente ao programador que o estado interno do objeto não está mudando - ótimo.

Se o estado está sendo afetado, e você precisa começar a tornar estáticas outras coisas para tornar a primeira coisa estática, é necessário perguntar quais partes precisam ser estáticas e quais não.

Sim , é um cheiro de código, apenas um pequeno.

user1775944
fonte
0

Torne-o um método estático e siga em frente. Não há nada errado com métodos estáticos. Depois que um padrão de uso surge, você pode se preocupar em abstrair o padrão.

davidk01
fonte
0

O cheiro aqui é que esse é um código processual envolto (minimamente) em objetos.

Deve haver uma razão pela qual você deseja executar essa operação na tabela de dados, mas, em vez de modelar essa operação com outras operações relacionadas que compartilham alguma semântica (ou seja, têm um significado comum), o autor acabou de criar um novo procedimento dentro de um novo classe e chamou.

Em uma linguagem funcional, é assim que você faria as coisas;) mas no paradigma OO, você deseja modelar algumas abstrações que incluem essa operação. Em seguida, você usaria técnicas de OO para detalhar esse modelo e fornecer um conjunto de operações relacionadas que preservam algumas semânticas.

Portanto, o principal cheiro aqui é que o autor está usando classes, provavelmente porque o compilador exige isso, sem organizar as operações em um modelo conceitual.

Observe sempre que você vê o programa sendo modelado em vez do espaço problemático . É um sinal de que o design pode se beneficiar de mais reflexão. Em outras palavras, cuidado com as classes, todas sendo "xAdaptor" e "xHandler" e "xUtility", e geralmente vinculadas a um modelo de domínio anêmico . Isso significa que alguém está apenas agrupando código por conveniência, em vez de modelar os conceitos que deseja implementar.

Roubar
fonte