Pergunta

Deixe-me começar por dizer que não defendo esta abordagem, mas vi-a recentemente e fiquei a pensar se haveria um nome para ela que pudesse usar para apontar a parte culpada.Então aqui vai.

Agora você tem um método e deseja retornar um valor.Você também deseja retornar um código de erro.É claro que exceções são uma escolha muito melhor, mas por alguma razão você deseja um código de erro.Lembre-se, estou bancando o advogado do diabo aqui.Então você cria uma classe genérica, assim:

class FunctionResult<T>
{
    public T payload;
    public int result;
}

E então declare suas funções assim:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

Uma variação desse padrão é usar um enum para o código de erro em vez de uma string.Agora, voltando à minha pergunta:existe um nome para isso e, em caso afirmativo, qual é?

Foi útil?

Solução

Eu concordo que isso não é especificamente um antipadrão.Pode ser um cheiro dependendo do uso.Existem razões pelas quais alguém realmente não desejaria usar exceções (por exemplo,os erros retornados não são 'excepcionais', para começar).

Há casos em que você deseja que um serviço retorne um modelo comum para seus resultados, incluindo erros e valores bons.Isto pode ser envolvido por uma interação de serviço de baixo nível que traduz o resultado em uma exceção ou outra estrutura de erro, mas no nível do serviço, permite que o serviço retorne um resultado e um código de status sem ter que definir alguma estrutura de exceção que possa têm que ser traduzidos através de uma fronteira remota.

Este código também pode não ser necessariamente um erro:considere uma resposta HTTP, que consiste em muitos dados diferentes, incluindo um código de status, juntamente com o corpo da resposta.

Outras dicas

Bem é isso não um antipadrão.A biblioteca padrão C++ faz uso desse recurso e o .NET ainda oferece um recurso especial FunctionResult classe no framework .NET.É chamado Nullable.Sim, isso não está restrito aos resultados de funções, mas pode ser usado nesses casos e é realmente muito útil aqui.Se o .NET 1.0 já tivesse o Nullable classe, certamente teria sido usado para o NumberType.TryParse métodos, em vez dos out parâmetro.

Normalmente passo a carga útil como referência (não const) e o código de erro como valor de retorno.

Sou desenvolvedor de jogos, banimos exceções

Konrad está certo, C# usa valores de retorno duplos o tempo todo.Mas eu gosto de TryParse, Dictionary.TryGetValue, etc.métodos em C#.

int value;
if (int.TryParse("123", out value)) {
    // use value
}

em vez de

int? value = int.TryParse("123");
if (value != null) {
    // use value
}

... principalmente porque o padrão Nullable não é dimensionado para tipos de retorno sem valor (ou seja, instâncias de classe).Isso não funcionaria com Dictionary.TryGetValue().E TryGetValue é melhor do que KeyNotFoundException (sem "exceções de primeira chance" constantemente no depurador, sem dúvida mais eficiente), melhor do que a prática de Java de get() retornar nulo (e se valores nulos forem esperados) e mais eficiente do que ter que chame ContasKey() primeiro.

Mas isso é ainda um pouco estranho - como se parece com C#, então deveria estar usando um parâmetro out.Todos os ganhos de eficiência provavelmente serão perdidos ao instanciar a classe.

(Poderia ser Java, exceto pelo tipo "string" estar em letras minúsculas.Em Java, é claro, você precisa usar uma classe para emular valores de retorno duplos.)

Não tenho certeza se isso é um antipadrão.Tenho visto isso comumente usado em vez de exceções por motivos de desempenho ou talvez para tornar mais explícito o fato de que o método pode falhar.Para mim, parece ser uma preferência pessoal e não um antipadrão.

Concordo com aqueles que dizem que isso não é um antipadrão.É um padrão perfeitamente válido em certos contextos.As exceções são para excepcional situações, os valores de retorno (como no seu exemplo) devem ser usados ​​em situações esperadas.Alguns domínios esperam resultados válidos e inválidos das classes, e nenhum deles deve ser modelado como exceção.

Por exemplo, dada uma quantidade X de gasolina, um carro pode ir de A a B e, em caso afirmativo, quanta gasolina sobra?Esse tipo de pergunta é ideal para a estrutura de dados que você forneceu.É esperado que não seja possível fazer a viagem de A para B, portanto, uma exceção não deve ser usada.

Essa abordagem é na verdade muito melhor do que algumas outras que já vi.Algumas funções em C, por exemplo, quando encontram um erro retornam e parecem ter sucesso.A única maneira de saber se eles falharam é chamar uma função que obterá o erro mais recente.

Passei horas tentando depurar o código do semáforo no meu MacBook antes de finalmente descobrir que sem_init não funciona no OSX!Ele compilou sem erros e foi executado sem causar erros - mas o semáforo não funcionou e eu não consegui descobrir o porquê.Tenho pena das pessoas que portam um aplicativo que usa Semáforos POSIX para OSX e deve lidar com problemas de contenção de recursos que já foram depurados.

Que tal o padrão "Não consigo decidir se isso é um erro ou não".Parece que se você realmente tivesse uma exceção, mas quisesse retornar um resultado parcial, você agruparia o resultado na exceção.

Se você não quiser usar exceções, a maneira mais limpa de fazer isso é fazer com que a função retorne o código de erro/sucesso e receba uma referência ou um argumento de ponteiro que é preenchido com o resultado.

Eu não chamaria isso de antipadrão.É um método viável muito comprovado e geralmente preferível ao uso de exceções.

Se você espera que seu método falhe ocasionalmente, mas não considera isso excepcional, prefiro este padrão usado no .NET Framework:

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}

Os debates sobre cheiros e antipadrões me lembram os programas de TV “Survivor”, onde você tem várias construções de programação tentando expulsar uns dos outros da ilha.Eu preferiria ver "a construção X tem tais prós e contras", em vez de uma lista em constante evolução de decretos sobre o que deve ou não ser feito.

Em defesa da designação antipadrão, este código pode ser usado de algumas maneiras:

  1. Objeto x = MinhaFunção().payload; (ignorando o resultado retornado - muito ruim)
  2. código interno = MinhaFunção().resultado; (jogar fora a carga útil - pode ser aceitável se esse for o uso pretendido.)
  3. FunctionResult x = MinhaFunção();//... (um monte de objetos FunctionResult extras e código extra para verificá-los em todos os lugares)

Se você precisar usar códigos de retorno, tudo bem.Mas então use códigos de retorno.Não tente incluir uma carga extra com ele.Isso é o que referência e fora parâmetros (C#) são para.Tipos anuláveis ​​podem ser uma exceção, mas apenas porque há açúcar extra na linguagem para apoiá-los.

Se você ainda discorda desta avaliação, NÃO VOTE nesta resposta (não na pergunta inteira).Se você acha que é um antipadrão, então UPVOTE.Usaremos esta resposta para ver o que a comunidade pensa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top