Pergunta

Digamos que estou escrevendo uma função para converter entre escalas de temperatura.Quero apoiar pelo menos Celsius, Fahrenheit e Kelvin.É melhor passar a escala de origem e a escala de destino como parâmetros separados da função ou algum tipo de parâmetro combinado?

Exemplo 1 - parâmetros separados:função convertTemperatura("celsius", "fahrenheit", 22)

Exemplo 2 – parâmetro combinado:função convertTemperature("c-f", 22)

O código dentro da função provavelmente é onde é importante.Com dois parâmetros, a lógica para determinar qual fórmula usaremos é um pouco mais complicada, mas um único parâmetro não parece certo de alguma forma.

Pensamentos?

Foi útil?

Solução

Escolha a primeira opção, mas em vez de permitir strings literais (que são propensas a erros), use valores constantes ou uma enumeração se sua linguagem suportar, como esta:

convertTemperature (TempScale.CELSIUS, TempScale.FAHRENHEIT, 22)

Outras dicas

Depende do idioma.

Geralmente, eu usaria argumentos separados com enumerações.

Se for uma linguagem orientada a objetos, eu recomendaria uma classe de temperatura, com a temperatura armazenada internamente como você quiser e, em seguida, funções para produzi-la em quaisquer unidades necessárias:

temp.celsius();// retorna a temperatura do objeto em Celsius

Ao escrever esses designs, gosto de pensar comigo mesmo: "Se eu precisasse adicionar uma unidade extra, o que o design tornaria mais fácil para fazê -lo?" Fazendo isso, chego à conclusão de que as enumes seriam mais fáceis pelos seguintes motivos:

1) Adicionar novos valores é fácil.2) Evito fazer comparação de strings

No entanto, como você escreve o método de conversão?3p2 é 6.Isso significa que existem 6 combinações diferentes de Celsius, Fahrenheit e Kelvin.E se eu quisesse adicionar um novo formato temperado “foo”?Isso significaria 4p2, que é 12!Mais dois?5p2 = 20 combinações.Mais três?6p2 = 30 combinações!

Você pode ver rapidamente como cada modificação adicional requer mais e mais alterações no código.Por esse motivo não faço conversões diretas!Em vez disso, faço uma conversão intermediária.Eu escolheria uma temperatura, digamos Kelvin.E inicialmente eu converteria para Kelvin.Eu então converteria kelvin para a temperatura desejada.Sim, isso resulta em um cálculo extra.No entanto, torna o escalonamento do código muito mais fácil.adicionar uma nova unidade de temperatura sempre resultará em apenas duas novas modificações no código.Fácil.

Algumas coisas:

  • Eu usaria um tipo enumerado que um verificador de sintaxe ou compilador pode verificar, em vez de uma string que pode ser digitada incorretamente.Em Pseudo-PHP:

    definir('kCelsius', 0);definir('kFarenheit', 1);definir ('kKelvin', 2);$a = ConvertTemperatura(22, kCelsius, kFarenheit);

Além disso, parece-me mais natural colocar aquilo em que você opera, neste caso a temperatura a ser convertida, primeiro.Dá uma ordem lógica aos seus parâmetros (converter - o quê?de?para?) e, portanto, ajuda com mnemônicos.

Sua função será muito mais robusta se você usar a primeira abordagem.Se você precisar adicionar outra escala, esse será mais um valor de parâmetro a ser manipulado.Na segunda abordagem, adicionar outra escala significa adicionar tantos valores quantos escalas você já tinha na lista, vezes 2.(Por exemplo, para adicionar K a C e F, você teria que adicionar KC, KF, CK e CF.)

Uma maneira decente de estruturar seu programa seria primeiro converter tudo o que entra em uma escala intermediária escolhida arbitrariamente e depois converter dessa escala intermediária para a escala de saída.

A melhor maneira seria ter uma pequena biblioteca de inclinações e interceptações para as diversas escalas, e apenas procurar os números das escalas de entrada e saída e fazer o cálculo em uma etapa genérica.

Em C # (e provavelmente em Java), seria melhor criar uma classe Temperature que armazenasse temperaturas de forma privada como Celsius (ou qualquer outra coisa) e que tivesse propriedades Celcius, Fahrenheit e Kelvin que fizessem todas as conversões para você em suas instruções get e set?

Depende de quantas conversões você terá.Eu provavelmente escolheria um parâmetro, fornecido como enum:Considere esta versão expandida de conversão.

enum Conversion
{
  CelsiusToFahrenheit,
  FahrenheitToCelsius,
  KilosToPounds
}

Convert(Conversion conversion, X from);

Agora você tem segurança de tipo sensata no ponto de chamada - não é possível fornecer parâmetros digitados corretamente que forneçam um resultado de tempo de execução incorreto.Considere a alternativa.

enum Units
{
  Pounds,
  Kilos,
  Celcius,
  Farenheight
}

Convert(Unit from, Unit to, X fromAmount);

Posso digitar com segurança ligar

Convert(Pounds, Celcius, 5, 10);

Mas o resultado não tem sentido e você terá que falhar em tempo de execução.Sim, eu sei que você está lidando apenas com temperatura no momento, mas o conceito geral ainda se mantém (acredito).

Eu escolheria

Exemplo 1 - parâmetros separados:função convertTemperatura("celsius", "fahrenheit", 22)

Caso contrário, dentro da sua definição de função, você teria que analisar "cf" em "celsius" e "fahrenheit" de qualquer maneira para obter as escalas de conversão necessárias, o que poderia ficar confuso.

Se você estiver fornecendo algo como a caixa de pesquisa do Google aos usuários, ter atalhos úteis como "cf" é bom para eles.Por baixo, porém, eu converteria "cf" em "celsius" e "fahrenheit" em uma função externa antes de chamar convertTemperature() como acima.

Neste caso, parâmetros únicos parecem totalmente obscuros;

Função converter temperatura de uma escala para outra escala.
Na IMO, é mais natural passar as escalas de origem e de destino como parâmetros separados.Definitivamente, não quero tentar entender o formato do primeiro argumento.

Eu faria uma enumeração dos tipos de temperatura e passaria os 2 parâmetros da escala.Algo como (em c#):


public void ConvertTemperature(TemperatureTypeEnum SourceTemp,
                               TemperatureTypeEnum TargetTemp, 
                               decimal Temperature)
{}

Estou sempre procurando maneiras de usar objetos para resolver meus problemas de programação.Espero que isso signifique que estou mais OO do que quando usava apenas funções para resolver problemas, mas isso ainda está para ser visto.

Em C#:

interface ITemperature
{
     CelciusTemperature ToCelcius();
     FarenheitTemperature ToFarenheit();
}

struct FarenheitTemperature : ITemperature
{
    public readonly int Value;
    public FarenheitTemperature(int value)
    {
        this.Value = value;
    }

    public FarenheitTemperature ToFarenheit() { return this; }
    public CelciusTemperature ToCelcius()
    {
        return new CelciusTemperature((this.Value - 32) * 5 / 9);
    }

}

struct CelciusTemperature
{
    public readonly int Value;
    public CelciusTemperature(int value)
    {
        this.Value = value;
    }

    public CelciusTemperature ToCelcius() { return this; }
    public FarenheitTemperature ToFarenheit()
    {
        return new FarenheitTemperature(this.Value * 9 / 5 + 32);
    }
}

e alguns testes:

        // Freezing
        Debug.Assert(new FarenheitTemperature(32).ToCelcius().Equals(new CelciusTemperature(0)));
        Debug.Assert(new CelciusTemperature(0).ToFarenheit().Equals(new FarenheitTemperature(32)));

        // crossover
        Debug.Assert(new FarenheitTemperature(-40).ToCelcius().Equals(new CelciusTemperature(-40)));
        Debug.Assert(new CelciusTemperature(-40).ToFarenheit().Equals(new FarenheitTemperature(-40)));

e um exemplo de bug que essa abordagem evita:

        CelciusTemperature theOutbackInAMidnightOilSong = new CelciusTemperature(45);
        FarenheitTemperature x = theOutbackInAMidnightOilSong; // ERROR: Cannot implicitly convert type 'CelciusTemperature' to 'FarenheitTemperature'

Adicionar conversões Kelvin é deixado como exercício.

A propósito, não precisa ser mais trabalhoso implementar a versão de três parâmetros, conforme sugerido no enunciado da pergunta.

Todas essas são funções lineares, então você pode implementar algo como

float LinearConvert(float in, float scale, float add, bool invert);

onde o último bool indica se você deseja fazer a transformação direta ou reversa.

Dentro da sua técnica de conversão, você pode ter um par escalar/adicionar para X -> Kelvin.Ao receber uma solicitação para converter o formato X em Y, você pode primeiro executar X -> Kelvin, depois Kelvin -> Y invertendo o processo Y -> Kelvin (invertendo o último bool para LinearConvert).

Essa técnica fornece algo como 4 linhas de código real em sua função de conversão e um dado para cada tipo entre os quais você precisa converter.

Semelhante ao que @Rob @wcm e @David explicaram...

public class Temperature
{
    private double celcius;

    public static Temperature FromFarenheit(double farenheit)
    {
        return new Temperature { Farhenheit = farenheit };
    }

    public static Temperature FromCelcius(double celcius)
    {
        return new Temperature { Celcius = celcius };
    }

    public static Temperature FromKelvin(double kelvin)
    {
        return new Temperature { Kelvin = kelvin };
    }

    private double kelvinToCelcius(double kelvin)
    {
        return 1; // insert formula here
    }

    private double celciusToKelvin(double celcius)
    {
        return 1; // insert formula here
    }

    private double farhenheitToCelcius(double farhenheit)
    {
        return 1; // insert formula here
    }

    private double celciusToFarenheit(double kelvin)
    {
        return 1; // insert formula here
    }

    public double Kelvin
    {
        get { return celciusToKelvin(celcius); }
        set { celcius = kelvinToCelcius(value); }
    }

    public double Celcius
    {
        get { return celcius; }
        set { celcius = value; }
    }

    public double Farhenheit
    {
        get { return celciusToFarenheit(celcius); }
        set { celcius = farhenheitToCelcius(value); }
    }
}

Acho que iria em uma direção ou outra.Você poderia escrever uma minilinguagem que fizesse qualquer tipo de conversão como unidades faz:

$ units 'tempF(-40)' tempC
    -40

Ou use funções individuais como a recente Converter::Temperatura O módulo Perl faz:

use Convert::Temperature;

my $c = new Convert::Temperature();

my $res = $c->from_fahr_to_cel('59');

Mas isso traz à tona um ponto importante: a linguagem que você está usando já possui funções de conversão?Em caso afirmativo, que convenção de codificação eles usam?Portanto, se a linguagem for C, seria melhor seguir o exemplo das funções da biblioteca atoi e strtod (não testadas):

double fahrtocel(double tempF){
    return ((tempF-32)*(5/9));
}

double celtofahr(double tempC){
    return ((9/5)*tempC + 32);
}

Ao escrever este post, me deparei com um postagem muito interessante sobre como usar o emacs para converter datas.A conclusão deste tópico é que ele usa o estilo de uma função por conversão.Além disso, as conversões podem ser muito obscuras.Costumo fazer cálculos de datas usando SQL porque parece improvável que haja muitos bugs nesse código.No futuro, analisarei o uso do emacs.

Aqui está minha opinião sobre isso (usando PHP):

function Temperature($value, $input, $output)
{
    $value = floatval($value);

    if (isset($input, $output) === true)
    {
        switch ($input)
        {
            case 'K': $value = $value - 273.15; break; // Kelvin
            case 'F': $value = ($value - 32) * (5 / 9); break; // Fahrenheit
            case 'R': $value = ($value - 491.67) * (5 / 9); break; // Rankine
        }

        switch ($output)
        {
            case 'K': $value = $value + 273.15; break; // Kelvin
            case 'F': $value = $value * (9 / 5) + 32; break; // Fahrenheit
            case 'R': $value = ($value + 273.15) * (9 / 5); break; // Rankine
        }
    }

    return $value;
}

Basicamente o $input O valor é convertido para a escala Celsius padrão e depois convertido novamente para a escala Celsius. $output escala - uma função para governar todos eles.=)

Meu voto são dois parâmetros para tipos de conversão, um para o valor (como no seu primeiro exemplo).Eu usaria enums em vez de literais de string, entretanto.

Use enums, se o seu idioma permitir, para as especificações da unidade.

Eu diria que o código interno seria mais fácil com dois.Eu teria uma tabela com pré-adição, multiplicação e pós-adição e executaria o valor no item de uma unidade e, em seguida, no item da outra unidade ao contrário.Basicamente convertendo a temperatura de entrada em um valor base comum interno e depois externo para a outra unidade.Toda essa função seria orientada por tabela.

Eu gostaria que houvesse alguma maneira de aceitar múltiplas respostas.Com base nas recomendações de todos, acho que continuarei com os vários parâmetros, alterando as strings para enums/constantes e movendo o valor a ser convertido para a primeira posição na lista de parâmetros.Dentro da função, usarei Kelvin como meio termo comum.

Anteriormente eu havia escrito funções individuais para cada conversão e a função convertTemperature() geral era apenas um wrapper com instruções switch aninhadas.Estou escrevendo tanto em ASP clássico quanto em PHP, mas queria deixar a questão em aberto para qualquer linguagem.

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