9

假设我正在编写一个在温标之间转换的函数。我想至少支持摄氏、华氏和开尔文。将源比例和目标比例作为函数的单独参数传递,还是某种组合参数更好?

示例 1 - 单独的参数:函数 convertTemperature("celsius", "fahrenheit", 22)

示例 2 - 组合参数:函数 convertTemperature("cf", 22)

函数内部的代码可能是它重要的地方。使用两个参数,确定我们要使用的公式的逻辑稍微复杂一些,但是单个参数感觉不太对劲。

想法?

4

18 回答 18

15

使用第一个选项,而不是允许文字字符串(容易出错),如果您的语言支持,则采用常量值或枚举,如下所示:

convertTemperature (TempScale.CELSIUS, TempScale.FAHRENHEIT, 22)
于 2008-09-12T14:21:43.150 回答
5

取决于语言。

通常,我会对枚举使用单独的参数。

如果它是一种面向对象的语言,那么我会推荐一个温度类,将温度存储在您喜欢的内部,然后以所需的任何单位输出它:

temp.celsius(); // 以摄氏度返回对象 temp 的温度

于 2008-09-12T14:33:28.147 回答
3

在编写这样的设计时,我喜欢对自己思考,“如果我需要添加一个额外的单元,那么设计会使其最容易做到吗?” 这样做,我得出的结论是枚举是最简单的,原因如下:

1) 添加新值很容易。2)我避免进行字符串比较

但是,转换方法怎么写呢?3p2 是 6。这意味着摄氏、华氏和开尔文有 6 种不同的组合。如果我想添加一个新的温和格式“foo”怎么办?这意味着 4p2 是 12!还有两个?5p2 = 20 组合。还有三个?6p2 = 30 种组合!

您可以快速查看每个附加修改如何需要对代码进行越来越多的更改。因此,我不进行直接转换!相反,我进行了中间转换。我会选择一种温度,开尔文说。最初,我会转换为开尔文。然后我将开尔文转换为所需的温度。是的,它确实会导致额外的计算。但是,它使代码更容易调用。添加一个新的温度单位总是只会导致对代码进行两次新的修改。简单的。

于 2008-09-12T14:29:51.070 回答
2

一些东西:

  • 我会使用语法检查器或编译器可以检查的枚举类型,而不是可能输入错误的字符串。在伪 PHP 中:

    定义('kCelsius',0);定义('kFarenheit',1);定义('kKelvin',2);$a = ConvertTemperature(22, kCelsius, kFarenheit);

另外,对我来说,首先放置您操作的东西似乎更自然,在这种情况下,首先要转换的温度。它为您的参数提供了逻辑顺序(转换 - 什么?从?到?),因此有助于助记符。

于 2008-09-12T14:25:31.847 回答
2

如果您使用第一种方法,您的功能将更加强大。如果您需要添加另一个比例,那就是要处理的另一个参数值。在第二种方法中,添加另一个比例意味着添加与列表中已有比例一样多的值,乘以 2。(例如,要将 K 添加到 C 和 F,您必须添加 KC、KF、CK 和CF。)

构建程序的一种体面方法是首先将输入的任何内容转换为任意选择的中间比例,然后从该中间比例转换为输出比例。

更好的方法是为各种尺度建立一个小的斜率和截距库,只需查找传入和传出尺度的数字,然后在一个通用步骤中进行计算。

于 2008-09-12T14:30:44.330 回答
2

在 C#(可能还有 Java)中,最好创建一个温度类,将温度私下存储为摄氏度(或其他),并具有摄氏度、华氏度和开尔文属性,可以在 get 和 set 语句中为您完成所有转换?

于 2008-09-12T15:00:59.983 回答
1

取决于您将进行多少次转换。我可能会选择一个参数,以枚举形式给出:考虑这个扩展版本的转换。

enum Conversion
{
  CelsiusToFahrenheit,
  FahrenheitToCelsius,
  KilosToPounds
}

Convert(Conversion conversion, X from);

您现在在调用点拥有健全的类型安全性 - 无法给出正确类型的参数,从而给出不正确的运行时结果。考虑替代方案。

enum Units
{
  Pounds,
  Kilos,
  Celcius,
  Farenheight
}

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

我可以安全地输入电话

Convert(Pounds, Celcius, 5, 10);

但是结果是没有意义的,你将不得不在运行时失败。是的,我知道您目前只处理温度,但一般概念仍然成立(我相信)。

于 2008-09-12T14:24:30.257 回答
1

我会枚举温度类型并传入 2 个比例参数。像(在 c# 中):


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

于 2008-09-12T14:24:52.020 回答
1

我会选

示例 1 - 单独的参数:函数 convertTemperature("celsius", "fahrenheit", 22)

否则,在您的函数定义中,您将不得不将“cf”解析为“celsius”和“fahrenheit”,以获得所需的转换比例,这可能会变得混乱。

如果您向用户提供诸如 Google 搜索框之类的内容,那么使用“cf”之类的便捷快捷方式对他们来说非常有用。不过,在下面,我会在外部函数中将“cf”转换为“celsius”和“fahrenheit”,然后再调用上面的 convertTemperature()。

于 2008-09-12T14:25:57.227 回答
1

在这种情况下,单个参数看起来完全模糊;

功能将温度一个刻度转换为另一个刻度
IMO 将源和目标比例作为单独的参数传递更为自然。我绝对不想尝试掌握第一个参数的格式。

于 2008-09-12T14:27:23.167 回答
1

我一直在寻找使用对象来解决我的编程问题的方法。我希望这意味着我比仅使用函数来解决问题时更加面向对象,但这还有待观察。

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

和一些测试:

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

以及这种方法避免的错误示例:

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

添加开尔文转换留作练习。

于 2008-09-12T14:49:34.923 回答
1

顺便说一句,正如问题陈述中所建议的那样,实现三参数版本不必做更多的工作。

这些都是线性函数,所以你可以实现类似

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

最后一个布尔值表示您是要进行正向变换还是反转它。

在您的转换技术中,您可以使用 X -> Kelvin 的比例/加法对。当您收到将格式 X 转换为 Y 的请求时,您可以先运行 X -> Kelvin,然后通过反转 Y -> Kelvin 过程(通过将最后一个布尔值翻转为 LinearConvert)运行 Kelvin -> Y。

这种技术在您的转换函数中为您提供了 4 行实际代码,并且为您需要在其之间转换的每种类型提供了一条数据。

于 2008-09-12T15:07:18.283 回答
1

类似于@Rob @wcm 和@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); }
    }
}
于 2008-09-12T15:23:55.530 回答
1

我想我会全力以赴。您可以编写一种迷你语言,它可以像单位一样进行任何类型的转换:

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

或者使用像最近的Convert::Temperature Perl 模块这样的单个函数:

use Convert::Temperature;

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

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

但这带来了一个重要的点——你使用的语言是否已经具有转换功能?如果是这样,他们使用什么编码约定?因此,如果语言是 C,最好遵循 atoi 和 strtod 库函数的示例(未经测试):

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

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

在写这篇文章时,我遇到了一篇关于使用 emacs 转换日期的非常有趣的文章。这个主题的要点是它使用了每次转换一个函数的风格。此外,转换可能非常模糊。我倾向于使用 SQL 进行日期计算,因为该代码中似乎不太可能有很多错误。将来,我将研究使用 emacs。

于 2008-09-12T17:09:49.580 回答
1

这是我对此的看法(使用 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;
}

基本上,该$input值被转换为标准摄氏刻度,然后再次转换回$output刻度 - 一个函数来统治它们。=)

于 2010-12-15T15:27:32.733 回答
0

我的投票是转换类型的两个参数,一个用于值(如您的第一个示例中所示)。但是,我会使用枚举而不是字符串文字。

于 2008-09-12T14:22:36.813 回答
0

如果您的语言允许,请使用枚举作为单位规范。

我想说两个里面的代码会更容易。我有一个带有预加、乘法和后加的表,并通过一个单元的项目运行值,然后反向运行另一个单元的项目。基本上将输入温度转换为内部的公共基础值,然后输出到另一个单元。这整个函数将是表驱动的。

于 2008-09-12T14:23:14.317 回答
0

我希望有某种方法可以接受多个答案。根据大家的建议,我想我会坚持使用多个参数,将字符串更改为枚举/常量,并将要转换的值移动到参数列表中的第一个位置。在函数内部,我将使用 Kelvin 作为一个共同的中间立场。

以前我为每个转换编写了单独的函数,整个 convertTemperature() 函数只是一个带有嵌套 switch 语句的包装器。我用经典的 ASP 和 PHP 编写,但我想把这个问题留给任何语言。

于 2008-09-13T01:33:08.280 回答