Pregunta

Digamos que estoy escribiendo una función para convertir entre escalas de temperatura.Quiero apoyar al menos grados Celsius, Fahrenheit y Kelvin.¿Es mejor pasar la escala de origen y la escala de destino como parámetros separados de la función, o algún tipo de parámetro combinado?

Ejemplo 1: parámetros separados:función convertirTemperatura("celsius", "fahrenheit", 22)

Ejemplo 2: parámetro combinado:función convertirTemperatura("c-f", 22)

El código dentro de la función probablemente sea lo que cuenta.Con dos parámetros, la lógica para determinar qué fórmula vamos a utilizar es un poco más complicada, pero un solo parámetro no parece correcto de alguna manera.

¿Pensamientos?

¿Fue útil?

Solución

Elija la primera opción, pero en lugar de permitir cadenas literales (que son propensas a errores), tome valores constantes o una enumeración si su idioma lo admite, como este:

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

Otros consejos

Depende del idioma.

Generalmente, usaría argumentos separados con enumeraciones.

Si es un lenguaje orientado a objetos, entonces recomendaría una clase de temperatura, con la temperatura almacenada internamente como quieras y luego funciona para generarla en las unidades que sean necesarias:

temperatura.celsius();// devuelve la temperatura del objeto temp en grados centígrados

Al escribir tales diseños, me gusta pensar a mí mismo: "Si necesitara agregar una unidad adicional, ¿qué sería el diseño más fácil de hacerlo?" Al hacer esto, llego a la conclusión de que enums sería más fácil por las siguientes razones:

1) Agregar nuevos valores es fácil.2) Evito hacer comparación de cadenas

Sin embargo, ¿cómo se escribe el método de conversión?3p2 es 6.Eso significa que hay 6 combinaciones diferentes de grados Celsius, Fahrenheit y Kelvin.¿Qué pasa si quisiera agregar un nuevo formato templado "foo"?¡Eso significaría 4p2 que es 12!¿Dos más?5p2 = 20 combinaciones.¿Tres más?6p2 = 30 combinaciones!

Puede ver rápidamente cómo cada modificación adicional requiere más y más cambios en el código.¡Por esta razón no hago conversiones directas!En lugar de eso, hago una conversión intermedia.Yo elegiría una temperatura, digamos Kelvin.E inicialmente, me convertiría a kelvin.Luego convertiría kelvin a la temperatura deseada.Sí, resulta en un cálculo adicional.Sin embargo, hace que escalar el código sea mucho más fácil.Agregar una nueva unidad de temperatura siempre dará como resultado solo dos nuevas modificaciones al código.Fácil.

Unas pocas cosas:

  • Usaría un tipo enumerado que un compilador o un verificador de sintaxis pueda verificar en lugar de una cadena que pueda escribirse mal.En pseudo-PHP:

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

Además me parece más natural colocar aquello sobre lo que se opera, en este caso la temperatura a convertir, primero.Da un orden lógico a sus parámetros (convertir, ¿qué?¿de?a?) y por lo tanto ayuda con la mnemónica.

Su función será mucho más sólida si utiliza el primer enfoque.Si necesita agregar otra escala, ese es un valor de parámetro más para manejar.En el segundo enfoque, agregar otra escala significa agregar tantos valores como escalas ya tenía en la lista, multiplicado por 2.(Por ejemplo, para sumar K a C y F, tendría que sumar K-C, K-F, C-K y C-F).

Una forma decente de estructurar su programa sería convertir primero lo que llegue a una escala intermedia elegida arbitrariamente y luego convertir de esa escala intermedia a la escala saliente.

Una mejor manera sería tener una pequeña biblioteca de pendientes e intersecciones para las distintas escalas, y simplemente buscar los números de las escalas entrantes y salientes y hacer el cálculo en un solo paso genérico.

En C# (y probablemente en Java), sería mejor crear una clase de temperatura que almacene las temperaturas de forma privada en grados Celsius (o lo que sea) y que tenga propiedades en grados Celsius, Fahrenheit y Kelvin que realicen todas las conversiones por usted en sus declaraciones get y set.

Depende de cuántas conversiones vayas a tener.Probablemente elegiría un parámetro, dado como enumeración:Considere esta versión ampliada de la conversión.

enum Conversion
{
  CelsiusToFahrenheit,
  FahrenheitToCelsius,
  KilosToPounds
}

Convert(Conversion conversion, X from);

Ahora tiene una seguridad de tipos sensata en el punto de llamada: no se pueden proporcionar parámetros escritos correctamente que den un resultado de tiempo de ejecución incorrecto.Considere la alternativa.

enum Units
{
  Pounds,
  Kilos,
  Celcius,
  Farenheight
}

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

Puedo escribir con seguridad llamar

Convert(Pounds, Celcius, 5, 10);

Pero el resultado no tiene sentido y tendrás que fallar en tiempo de ejecución.Sí, sé que por el momento solo estás tratando con la temperatura, pero el concepto general aún se mantiene (creo).

yo elegiría

Ejemplo 1: parámetros separados:función convertirTemperatura("celsius", "fahrenheit", 22)

De lo contrario, dentro de la definición de su función, tendría que analizar "c-f" en "celsius" y "fahrenheit" de todos modos para obtener las escalas de conversión requeridas, lo que podría resultar complicado.

Si proporciona algo como el cuadro de búsqueda de Google a los usuarios, tener accesos directos útiles como "c-f" es bueno para ellos.Debajo, sin embargo, convertiría "c-f" en "celsius" y "fahrenheit" en una función externa antes de llamar a convertTemperature() como se indicó anteriormente.

En este caso, los parámetros individuales parecen totalmente oscuros;

conversión de función temperatura de una escala a otra escala.
En mi opinión, es más natural pasar las escalas de origen y de destino como parámetros separados.Definitivamente no quiero intentar captar el formato del primer argumento.

Haría una enumeración de los tipos de temperatura y pasaría los 2 parámetros de escala.Algo como (en c#):


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

Siempre estoy buscando formas de utilizar objetos para resolver mis problemas de programación.Espero que esto signifique que soy más OO que cuando solo usaba funciones para resolver problemas, pero eso está por verse.

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

y algunas pruebas:

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

y un ejemplo de un error que este enfoque evita:

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

Sumar conversiones Kelvin se deja como ejercicio.

Por cierto, no tiene por qué ser más trabajo implementar la versión de tres parámetros, como se sugiere en el enunciado de la pregunta.

Todas estas son funciones lineales, por lo que puedes implementar algo como

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

donde el último bool indica si desea realizar la transformación hacia adelante o revertirla.

Dentro de su técnica de conversión, puede tener un par de escala/agregar para X -> Kelvin.Cuando recibe una solicitud para convertir el formato X a Y, primero puede ejecutar X -> Kelvin, luego Kelvin -> Y invirtiendo el proceso Y -> Kelvin (cambiando el último bool a LinearConvert).

Esta técnica le brinda algo así como 4 líneas de código real en su función de conversión y un dato para cada tipo entre el que necesita convertir.

Similar a lo que @Rob @wcm y @David explicaron...

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

Creo que iría por completo en una dirección u otra.Podrías escribir un minilenguaje que realice cualquier tipo de conversión como unidades hace:

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

O utilizar funciones individuales como la reciente Convertir::Temperatura El módulo Perl hace:

use Convert::Temperature;

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

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

Pero eso plantea un punto importante: ¿el idioma que estás utilizando ya tiene funciones de conversión?Si es así, ¿qué convención de codificación utilizan?Entonces, si el lenguaje es C, sería mejor seguir el ejemplo de las funciones de la biblioteca atoi y strtod (no probadas):

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

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

Al escribir esta publicación, me encontré con un publicación muy interesante sobre el uso de emacs para convertir fechas.La conclusión de este tema es que utiliza el estilo de una función por conversión.Además, las conversiones pueden ser muy oscuras.Tiendo a hacer cálculos de fechas usando SQL porque parece poco probable que haya muchos errores en ese código.En el futuro, consideraré el uso de emacs.

Aquí está mi opinión sobre esto (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;
}

Básicamente el $input El valor se convierte a la escala Celsius estándar y luego se vuelve a convertir a la escala Celsius. $output escala: una función para gobernarlos a todos.=)

Mi voto son dos parámetros para los tipos de conversión, uno para el valor (como en su primer ejemplo).Sin embargo, usaría enumeraciones en lugar de cadenas literales.

Utilice enumeraciones, si su idioma lo permite, para las especificaciones de la unidad.

Yo diría que el código interno sería más fácil con dos.Tendría una tabla con suma previa, multiplicación y suma posterior, y ejecutaría el valor a través del artículo para una unidad, y luego a través del artículo para la otra unidad a la inversa.Básicamente, convertir la temperatura de entrada a un valor base común en el interior y luego a la otra unidad.Toda esta función estaría basada en tablas.

Ojalá hubiera alguna forma de aceptar múltiples respuestas.Según las recomendaciones de todos, creo que me quedaré con los parámetros múltiples, cambiando las cadenas a enumeraciones/constantes y moviendo el valor a convertir a la primera posición en la lista de parámetros.Dentro de la función, usaré Kelvin como término medio común.

Anteriormente había escrito funciones individuales para cada conversión y la función convertTemperature() general era simplemente un contenedor con declaraciones de cambio anidadas.Estoy escribiendo tanto en ASP clásico como en PHP, pero quería dejar la pregunta abierta a cualquier idioma.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top