Question

Disons que j'écris une fonction pour convertir entre les échelles de température.Je souhaite prendre en charge au moins Celsius, Fahrenheit et Kelvin.Est-il préférable de transmettre l'échelle source et l'échelle cible en tant que paramètres distincts de la fonction, ou une sorte de paramètre combiné ?

Exemple 1 - paramètres séparés :fonction convertTemperature("celsius", "fahrenheit", 22)

Exemple 2 - paramètre combiné :fonction convertTemperature("c-f", 22)

Le code à l’intérieur de la fonction est probablement là où il compte.Avec deux paramètres, la logique pour déterminer quelle formule nous allons utiliser est légèrement plus compliquée, mais un seul paramètre ne semble pas correct d'une manière ou d'une autre.

Pensées?

Était-ce utile?

La solution

Optez pour la première option, mais plutôt que d'autoriser les chaînes littérales (qui sont sujettes aux erreurs), prenez des valeurs constantes ou une énumération si votre langage le prend en charge, comme ceci :

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

Autres conseils

Cela dépend de la langue.

Généralement, j'utiliserais des arguments séparés avec des énumérations.

S'il s'agit d'un langage orienté objet, je recommanderais une classe de température, avec la température stockée en interne comme vous le souhaitez, puis des fonctions pour la produire dans les unités nécessaires :

temp.celsius();// renvoie la température de l'objet en degrés Celsius

En écrivant de tels conceptions, j'aime me penser: "Si j'avais besoin d'ajouter une unité supplémentaire, qu'est-ce que le design le ferait le plus facile à faire?" En faisant cela, j'arrive à la conclusion que les énumérations seraient les plus faciles pour les raisons suivantes:

1) L’ajout de nouvelles valeurs est facile.2) J'évite de faire des comparaisons de chaînes

Cependant, comment écrire la méthode de conversion ?3p2 vaut 6.Cela signifie donc qu’il existe 6 combinaisons différentes de Celsius, Fahrenheit et Kelvin.Et si je voulais ajouter un nouveau format tempéré « foo » ?Cela signifierait 4p2, soit 12 !Deux de plus?5p2 = 20 combinaisons.Trois de plus?6p2 = 30 combinaisons !

Vous pouvez rapidement voir comment chaque modification supplémentaire nécessite de plus en plus de changements dans le code.Pour cette raison, je ne fais pas de conversions directes !Au lieu de cela, je fais une conversion intermédiaire.Je choisirais une température, disons Kelvin.Et au départ, je convertirais en Kelvin.Je convertirais ensuite le kelvin en la température souhaitée.Oui, cela entraîne un calcul supplémentaire.Cependant, cela facilite grandement la mise à l'échelle du code.l'ajout d'une nouvelle unité de température entraînera toujours seulement deux nouvelles modifications du code.Facile.

Quelques choses:

  • J'utiliserais un type énuméré qu'un vérificateur de syntaxe ou un compilateur peut vérifier plutôt qu'une chaîne qui peut être mal saisie.En pseudo-PHP :

    définir ('kCelsius', 0);définir ('kFarenheit', 1);définir ('kKelvin', 2);$a = ConvertTemperature(22, kCelsius, kFarenheit) ;

Aussi, il me semble plus naturel de placer l'objet sur lequel on opère, en l'occurrence la température à convertir, d'abord.Cela donne un ordre logique à vos paramètres (convertir - quoi ?depuis?à?) et aide ainsi avec les mnémoniques.

Votre fonction sera beaucoup plus robuste si vous utilisez la première approche.Si vous devez ajouter une autre échelle, cela représente une valeur de paramètre supplémentaire à gérer.Dans la deuxième approche, ajouter une autre échelle signifie ajouter autant de valeurs que vous aviez déjà d’échelles dans la liste, multiplié par 2.(Par exemple, pour ajouter K à C et F, vous devrez ajouter K-C, K-F, C-K et C-F.)

Une façon décente de structurer votre programme serait de convertir d'abord tout ce qui entre dans une échelle intermédiaire arbitrairement choisie, puis de convertir de cette échelle intermédiaire à l'échelle sortante.

Une meilleure façon serait d'avoir une petite bibliothèque de pentes et d'intersections pour les différentes échelles, de rechercher simplement les nombres pour les échelles entrantes et sortantes et d'effectuer le calcul en une seule étape générique.

En C# (et probablement Java), il serait préférable de créer une classe Temperature qui stocke les températures en privé sous forme de Celsius (ou autre) et qui possède des propriétés Celcius, Fahrenheit et Kelvin qui effectuent toutes les conversions pour vous dans leurs instructions get et set ?

Cela dépend du nombre de conversions que vous allez avoir.Je choisirais probablement un paramètre, donné sous forme d'énumération :Considérez cette version étendue de la conversion.

enum Conversion
{
  CelsiusToFahrenheit,
  FahrenheitToCelsius,
  KilosToPounds
}

Convert(Conversion conversion, X from);

Vous disposez désormais d'une sécurité de type saine au point d'appel - on ne peut pas donner des paramètres correctement saisis qui donnent un résultat d'exécution incorrect.Considérez l’alternative.

enum Units
{
  Pounds,
  Kilos,
  Celcius,
  Farenheight
}

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

Je peux écrire en toute sécurité et appeler

Convert(Pounds, Celcius, 5, 10);

Mais le résultat n’a aucun sens et vous devrez échouer au moment de l’exécution.Oui, je sais que vous ne parlez que de température pour le moment, mais le concept général est toujours valable (je crois).

je choisirais

Exemple 1 - paramètres séparés :fonction convertTemperature("celsius", "fahrenheit", 22)

Sinon, dans la définition de votre fonction, vous devrez de toute façon analyser "cf" en "celsius" et "fahrenheit" pour obtenir les échelles de conversion requises, ce qui pourrait devenir compliqué.

Si vous proposez aux utilisateurs quelque chose comme le champ de recherche de Google, disposer de raccourcis pratiques tels que « c-f » est bien pour eux.En dessous, cependant, je convertirais "cf" en "celsius" et "fahrenheit" dans une fonction externe avant d'appeler convertTemperature() comme ci-dessus.

Dans ce cas, les paramètres individuels semblent totalement obscurs ;

Conversion de fonction température depuis une échelle à une autre échelle.
OMI, il est plus naturel de transmettre les échelles source et cible en tant que paramètres distincts.Je ne veux certainement pas essayer de saisir le format du premier argument.

Je ferais une énumération des types de température et transmettrais les 2 paramètres d'échelle.Quelque chose comme (en c#) :


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

Je suis toujours à la recherche de moyens d'utiliser des objets pour résoudre mes problèmes de programmation.J'espère que cela signifie que je suis plus OO que lorsque j'utilisais uniquement des fonctions pour résoudre des problèmes, mais cela reste à voir.

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

et quelques tests :

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

et un exemple de bug que cette approche évite :

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

L'ajout de conversions Kelvin reste un exercice.

Soit dit en passant, il n'est pas nécessaire de travailler davantage pour implémenter la version à trois paramètres, comme suggéré dans l'énoncé de la question.

Ce sont toutes des fonctions linéaires, vous pouvez donc implémenter quelque chose comme

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

où le dernier booléen indique si vous souhaitez effectuer la transformation directe ou l'inverser.

Dans votre technique de conversion, vous pouvez avoir une paire échelle/ajout pour X -> Kelvin.Lorsque vous recevez une demande de conversion du format X en Y, vous pouvez d'abord exécuter X -> Kelvin, puis Kelvin -> Y en inversant le processus Y -> Kelvin (en retournant le dernier bool en LinearConvert).

Cette technique vous donne quelque chose comme 4 lignes de code réel dans votre fonction de conversion et un élément de données pour chaque type entre lequel vous devez effectuer une conversion.

Semblable à ce que @Rob @wcm et @David ont expliqué...

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

Je pense que j'irais à fond dans une direction ou dans une autre.Vous pouvez écrire un mini-langage qui effectue n'importe quel type de conversion comme unités fait:

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

Ou utilisez des fonctions individuelles comme la récente Convertir : Température Le module Perl fait :

use Convert::Temperature;

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

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

Mais cela soulève un point important : le langage que vous utilisez possède-t-il déjà des fonctions de conversion ?Si oui, quelle convention de codage utilisent-ils ?Donc si le langage est C, il serait préférable de suivre l'exemple des fonctions des bibliothèques atoi et strtod (non testées) :

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

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

En écrivant cet article, je suis tombé sur un article très intéressant sur l'utilisation d'emacs pour convertir des dates.Ce qu'il faut retenir de ce sujet est qu'il utilise le style une fonction par conversion.De plus, les conversions peuvent être très obscures.J'ai tendance à faire des calculs de date en utilisant SQL car il semble peu probable qu'il y ait beaucoup de bugs dans ce code.À l’avenir, j’envisagerai d’utiliser Emacs.

Voici mon point de vue (en utilisant 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;
}

Fondamentalement le $input La valeur est convertie à l'échelle Celsius standard, puis reconvertie à l'échelle $output échelle - une fonction pour les gouverner tous.=)

Mon vote concerne deux paramètres pour les types de conversion, un pour la valeur (comme dans votre premier exemple).J'utiliserais cependant des énumérations au lieu de chaînes littérales.

Utilisez des énumérations, si votre langue le permet, pour les spécifications de l'unité.

Je dirais que le code à l'intérieur serait plus facile avec deux.J'aurais une table avec pré-ajout, multiplication et post-ajout, et j'exécuterais la valeur via l'élément pour une unité, puis via l'élément pour l'autre unité en sens inverse.Fondamentalement, convertir la température d'entrée en une valeur de base commune à l'intérieur, puis vers l'autre unité.Toute cette fonction serait pilotée par une table.

J'aimerais qu'il y ait un moyen d'accepter plusieurs réponses.Sur la base des recommandations de chacun, je pense que je vais m'en tenir aux multiples paramètres, en changeant les chaînes en énumérations/constantes et en déplaçant la valeur à convertir vers la première position de la liste des paramètres.À l'intérieur de la fonction, j'utiliserai Kelvin comme terrain d'entente.

Auparavant, j'avais écrit des fonctions individuelles pour chaque conversion et la fonction globale convertTemperature() n'était qu'un wrapper avec des instructions switch imbriquées.J'écris à la fois en ASP classique et en PHP, mais je voulais laisser la question ouverte à n'importe quel langage.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top