Domanda

Diciamo che sto scrivendo una funzione per convertire tra scale di temperatura.Voglio supportare almeno Celsius, Fahrenheit e Kelvin.È meglio passare la scala di origine e quella di destinazione come parametri separati della funzione o come una sorta di parametro combinato?

Esempio 1 - parametri separati:funzione convertTemperatura("celsius", "fahrenheit", 22)

Esempio 2 - parametro combinato:funzione convertTemperatura("c-f", 22)

Il codice all'interno della funzione è probabilmente il punto che conta.Con due parametri, la logica per determinare quale formula utilizzeremo è leggermente più complicata, ma in qualche modo un singolo parametro non sembra corretto.

Pensieri?

È stato utile?

Soluzione

Scegli la prima opzione, ma invece di consentire stringhe letterali (che sono soggette a errori), prendi valori costanti o un'enumerazione se la tua lingua lo supporta, in questo modo:

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

Altri suggerimenti

Dipende dalla lingua.

In generale, utilizzerei argomenti separati con le enumerazioni.

Se è un linguaggio orientato agli oggetti, allora consiglierei una classe di temperatura, con la temperatura memorizzata internamente come preferisci e quindi funzioni per visualizzarla in qualunque unità sia necessaria:

temp.celsius();// restituisce la temperatura dell'oggetto in gradi Celsius

Quando scrivo tali design, mi piace pensare a me stesso: "Se avessi bisogno di aggiungere un'unità extra, cosa farebbe il design più facile farlo?" In questo modo, arrivo alla conclusione che Enums sarebbe più facile per i seguenti motivi:

1) Aggiungere nuovi valori è facile.2) Evito di fare il confronto tra stringhe

Tuttavia, come si scrive il metodo di conversione?3p2 è 6.Ciò significa che ci sono 6 diverse combinazioni di Celsius, Fahrenheit e Kelvin.E se volessi aggiungere un nuovo formato temperato "foo"?Ciò significherebbe 4p2 che fa 12!Ancora due?5p2 = 20 combinazioni.Altri tre?6p2 = 30 combinazioni!

Puoi vedere rapidamente come ogni modifica aggiuntiva richieda sempre più modifiche al codice.Per questo motivo non faccio conversioni dirette!Invece, eseguo una conversione intermedia.Sceglierei una temperatura, diciamo Kelvin.E inizialmente, mi convertirei in Kelvin.Quindi convertirei i Kelvin alla temperatura desiderata.Sì, comporta un calcolo aggiuntivo.Tuttavia, rende il ridimensionamento del codice molto più semplice.l'aggiunta di una nuova unità di temperatura comporterà sempre solo due nuove modifiche al codice.Facile.

Poche cose:

  • Utilizzerei un tipo enumerato che un correttore di sintassi o un compilatore può controllare anziché una stringa che può essere digitata in modo errato.Nello pseudo-PHP:

    definire('kCelsius', 0);definire('kFarenheit', 1);definire('kKelvin', 2);$a = ConvertiTemperatura(22, kCelsius, kFarenheit);

Inoltre mi sembra più naturale posizionare l'oggetto su cui si opera, in questo caso la temperatura da convertire, Primo.Fornisce un ordinamento logico ai tuoi parametri (convertire - cosa?da?a?) e quindi aiuta con la mnemotecnica.

La tua funzione sarà molto più robusta se utilizzi il primo approccio.Se è necessario aggiungere un'altra scala, si tratta di un valore di parametro in più da gestire.Nel secondo approccio, aggiungere un'altra scala significa aggiungere tanti valori quante sono le scale già presenti nell'elenco, moltiplicate per 2.(Ad esempio, per aggiungere K a C e F, dovresti aggiungere K-C, K-F, C-K e C-F.)

Un modo decente per strutturare il tuo programma sarebbe quello di convertire prima tutto ciò che arriva in una scala intermedia scelta arbitrariamente, e poi convertire da quella scala intermedia alla scala in uscita.

Un modo migliore sarebbe avere una piccola libreria di pendenze e intercettazioni per le varie scale, cercare semplicemente i numeri per le scale in entrata e in uscita ed eseguire il calcolo in un passaggio generico.

In C# (e probabilmente Java) sarebbe meglio creare una classe Temperature che memorizzi le temperature privatamente come Celcius (o qualsiasi altra cosa) e che abbia proprietà Celcius, Fahrenheit e Kelvin che eseguono tutte le conversioni per te nelle loro istruzioni get e set?

Dipende da quante conversioni avrai.Probabilmente sceglierei un parametro, dato come enum:Considera questa versione ampliata della conversione.

enum Conversion
{
  CelsiusToFahrenheit,
  FahrenheitToCelsius,
  KilosToPounds
}

Convert(Conversion conversion, X from);

Ora hai una sana sicurezza del tipo al momento della chiamata: non è possibile fornire parametri digitati correttamente che diano un risultato di runtime errato.Considera l'alternativa.

enum Units
{
  Pounds,
  Kilos,
  Celcius,
  Farenheight
}

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

Posso digitare tranquillamente chiamare

Convert(Pounds, Celcius, 5, 10);

Ma il risultato non ha senso e dovrai fallire in fase di esecuzione.Sì, lo so che al momento ti occupi solo della temperatura, ma il concetto generale è ancora valido (credo).

sceglierei

Esempio 1 - parametri separati:funzione convertTemperatura("celsius", "fahrenheit", 22)

Altrimenti all'interno della definizione della funzione dovresti comunque analizzare "cf" in "celsius" e "fahrenheit" per ottenere le scale di conversione richieste, il che potrebbe creare confusione.

Se fornisci agli utenti qualcosa come la casella di ricerca di Google, avere comode scorciatoie come "cf" è utile per loro.Sotto, però, convertirei "c-f" in "celsius" e "fahrenheit" in una funzione esterna prima di chiamare convertTemperature() come sopra.

In questo caso i singoli parametri appaiono totalmente oscuri;

Converti funzione temperatura da una scala A un'altra scala.
IMO è più naturale passare le scale sorgente e destinazione come parametri separati.Sicuramente non voglio provare a cogliere il formato del primo argomento.

Vorrei fare un'enumerazione dei tipi di temperatura e inserire i 2 parametri della scala.Qualcosa come (in C#):


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

Sono sempre alla ricerca di modi per utilizzare gli oggetti per risolvere i miei problemi di programmazione.Spero che questo significhi che sono più OO rispetto a quando usavo solo le funzioni per risolvere i problemi, ma resta da vedere.

In 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 alcuni test:

        // 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 un esempio di un bug che questo approccio evita:

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

L'aggiunta delle conversioni Kelvin viene lasciata come esercizio.

A proposito, non deve essere necessario ulteriore lavoro per implementare la versione a tre parametri, come suggerito nella dichiarazione della domanda.

Queste sono tutte funzioni lineari, quindi puoi implementare qualcosa di simile

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

dove l'ultimo bool indica se vuoi eseguire la trasformazione in avanti o invertirla.

All'interno della tua tecnica di conversione, puoi avere una coppia scala/addizione per X -> Kelvin.Quando ricevi una richiesta per convertire il formato X in Y, puoi prima eseguire X -> Kelvin, quindi Kelvin -> Y invertendo il processo Y -> Kelvin (invertendo l'ultimo bool in LinearConvert).

Questa tecnica ti fornisce qualcosa come 4 righe di codice reale nella tua funzione di conversione e un pezzo di dati per ogni tipo tra cui devi convertire.

Simile a quanto spiegato da @Rob @wcm e @David...

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); }
    }
}

Penso che andrei fino in fondo in una direzione o nell'altra.Potresti scrivere un mini-linguaggio che esegua qualsiasi tipo di conversione come unità fa:

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

Oppure utilizza le singole funzioni come il recente Converti::Temperatura Il modulo Perl fa:

use Convert::Temperature;

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

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

Ma questo solleva un punto importante: la lingua che stai utilizzando ha già funzioni di conversione?Se sì, quale convenzione di codifica usano?Quindi se il linguaggio è C, sarebbe meglio seguire l'esempio delle funzioni di libreria atoi e strtod (non testate):

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

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

Nello scrivere questo post, mi sono imbattuto in a post molto interessante sull'uso di emacs per convertire le date.Il punto fondamentale di questo argomento è che utilizza lo stile una funzione per conversione.Inoltre, le conversioni possono essere molto oscure.Tendo a eseguire calcoli sulle date utilizzando SQL perché sembra improbabile che ci siano molti bug in quel codice.In futuro, esaminerò l'utilizzo di emacs.

Ecco la mia opinione su questo (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;
}

Fondamentalmente il $input il valore viene convertito nella scala Celsius standard e quindi riconvertito nella scala Celsius $output scala: una funzione per domarli tutti.=)

Il mio voto è due parametri per i tipi di conversione, uno per il valore (come nel tuo primo esempio).Tuttavia, utilizzerei enumerazioni invece di stringhe letterali.

Utilizza le enumerazioni, se la tua lingua lo consente, per le specifiche dell'unità.

Direi che il codice all'interno sarebbe più semplice con due.Avrei una tabella con pre-aggiunta, moltiplicazione e post-aggiunta ed eseguirei il valore attraverso l'elemento per un'unità, quindi attraverso l'elemento per l'altra unità al contrario.Fondamentalmente converte la temperatura in ingresso in un valore base comune all'interno e poi all'altra unità.L'intera funzione sarebbe guidata da tabelle.

Vorrei che ci fosse un modo per accettare più risposte.Sulla base dei consigli di tutti, penso che resterò con i parametri multipli, cambiando le stringhe in enumerazioni/costanti e spostando il valore da convertire nella prima posizione nell'elenco dei parametri.All'interno della funzione utilizzerò Kelvin come via di mezzo comune.

In precedenza avevo scritto funzioni individuali per ciascuna conversione e la funzione complessiva convertTemperature() era semplicemente un wrapper con istruzioni switch nidificate.Sto scrivendo sia in ASP classico che in PHP, ma volevo lasciare la questione aperta a qualsiasi linguaggio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top