题
假设我正在编写一个在温标之间进行转换的函数。我想至少支持摄氏度、华氏度和开尔文。将源比例和目标比例作为函数的单独参数传递还是某种组合参数传递更好?
示例 1 - 单独的参数:函数转换温度(“摄氏度”,“华氏度”,22)
示例 2 - 组合参数:函数convertTemperature("c-f", 22)
函数内部的代码可能才是最重要的。使用两个参数,确定我们将使用什么公式的逻辑稍微复杂一些,但单个参数不知何故感觉不太正确。
想法?
解决方案
使用第一个选项,但不要允许文字字符串(这很容易出错),而是采用常量值或枚举(如果您的语言支持),如下所示:
convertTemperature (TempScale.CELSIUS, TempScale.FAHRENHEIT, 22)
其他提示
取决于语言。
一般来说,我会使用带有枚举的单独参数。
如果它是面向对象的语言,那么我会推荐一个温度类,根据您的喜好将温度存储在内部,然后使用所需的任何单位输出它:
温度.摄氏度();// 返回对象 temp 的温度(摄氏度)
在编写这样的设计时,我想对自己思考:“如果我需要添加一个额外的单元,那么什么设计将使最容易这样做?”这样做,我得出的结论是,出于以下原因,枚举将是最容易的:
1)添加新值很容易。2)我避免进行字符串比较
但是,转换方法怎么写呢?3p2 是 6。这意味着有 6 种不同的摄氏度、华氏度和开尔文组合。如果我想添加新的温带格式“foo”怎么办?这意味着 4p2,即 12!还有两个?5p2 = 20 组合。还有三个?6p2 = 30 种组合!
您可以快速了解每个额外的修改如何需要对代码进行越来越多的更改。因此,我不进行直接转换!相反,我会进行中间转换。开尔文说,我会选择一种温度。最初,我会转换为开尔文。然后我将开尔文转换为所需的温度。是的,它确实会导致额外的计算。然而,它使代码的扩展变得更加容易。添加新的温度单位始终只会导致对代码进行两次新的修改。简单的。
一些东西:
我会使用语法检查器或编译器可以检查的枚举类型,而不是可能输入错误的字符串。在伪 PHP 中:
定义('千摄氏度',0);定义('k华氏温度', 1);定义('kKelvin',2);$a = ConvertTemperature(22, k摄氏度, k华氏度);
另外,对我来说,放置你操作的东西似乎更自然,在这种情况下是要转换的温度, 第一的. 。它为您的参数提供了逻辑顺序(转换 - 什么?从?到?),从而有助于记忆。
如果您使用第一种方法,您的函数将会更加强大。如果您需要添加另一个比例,则需要处理另一个参数值。在第二种方法中,添加另一个比例意味着添加与列表中已有比例一样多的值,乘以 2。(例如,要将 K 添加到 C 和 F,您必须添加 K-C、K-F、C-K 和 C-F。)
构建程序的一个不错的方法是首先将输入的任何内容转换为任意选择的中间比例,然后从该中间比例转换为输出比例。
一种更好的方法是拥有一个针对各种比例的斜率和截距的小型库,只需查找传入和传出比例的数字并在一个通用步骤中进行计算即可。
在 C#(可能还有 Java)中,最好创建一个Temperature 类,将温度私下存储为摄氏温度(或其他),并且具有摄氏温度、华氏温度和开尔文属性,可以在其 get 和 set 语句中为您完成所有转换?
取决于您将获得多少转化。我可能会选择一个参数,以枚举形式给出:考虑这个转换的扩展版本。
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);
但结果是没有意义的,你必须在运行时失败。是的,我知道你现在只处理温度,但一般概念仍然成立(我相信)。
我会选
示例 1 - 单独的参数:函数转换温度(“摄氏度”,“华氏度”,22)
否则,在函数定义中,您必须将“c-f”解析为“摄氏度”和“华氏度”才能获得所需的转换比例,这可能会变得混乱。
如果您向用户提供类似 Google 搜索框的功能,那么拥有“c-f”等方便的快捷键对他们来说会很好。不过,在下面,我会在调用上面的 ConvertTemperature() 之前在外部函数中将“c-f”转换为“摄氏度”和“华氏度”。
在这种情况下,单个参数看起来完全晦涩难懂;
函数转换 温度 从 一个尺度 到 另一个尺度.
IMO 将源尺度和目标尺度作为单独的参数传递更为自然。我绝对不想尝试掌握第一个参数的格式。
我会枚举温度类型并传入 2 个比例参数。类似于(在 c# 中):
public void ConvertTemperature(TemperatureTypeEnum SourceTemp,
TemperatureTypeEnum TargetTemp,
decimal Temperature)
{}
我一直在寻找使用对象来解决编程问题的方法。我希望这意味着我比只使用函数解决问题时更加面向对象,但这还有待观察。
在 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'
添加开尔文转换作为练习。
顺便说一句,正如问题陈述中所建议的那样,实现三参数版本不需要做更多的工作。
这些都是线性函数,所以你可以实现类似的东西
float LinearConvert(float in, float scale, float add, bool invert);
其中最后一个布尔值指示是否要进行正向变换或反向变换。
在您的转换技术中,您可以为 X -> 开尔文提供缩放/相加对。当您收到将格式 X 转换为 Y 的请求时,您可以首先运行 X -> Kelvin,然后通过反转 Y -> Kelvin 过程(通过将最后一个布尔值翻转为 LinearConvert)来运行 Kelvin -> Y。
这种技术在转换函数中为您提供了大约 4 行实际代码,并为您需要在之间进行转换的每种类型提供了一段数据。
类似于@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); }
}
}
我想我会向一个或另一个方向全力以赴。您可以编写一种迷你语言来执行任何类型的转换,例如 单位 做:
$ units 'tempF(-40)' tempC
-40
或者使用像最近这样的单独功能 转换::温度 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。
这是我对此的看法(使用 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
规模——一种功能可以统治一切。=)
我的投票是两个用于转换类型的参数,一个用于值(如第一个示例中所示)。不过,我会使用枚举而不是字符串文字。
如果您的语言允许,请使用枚举作为单位规格。
我想说里面的代码有两个会更容易。我有一张包含预加、多重和后加的表,并通过一个单位的项目运行该值,然后反向运行另一个单位的项目。基本上将输入温度转换为内部的公共基值,然后输出到另一个单位。整个函数将由表驱动。
我希望有某种方法可以接受多个答案。根据大家的建议,我想我会坚持使用多个参数,将字符串更改为枚举/常量,并将要转换的值移动到参数列表中的第一个位置。在函数内部,我将使用开尔文作为共同的中间立场。
以前,我为每个转换编写了单独的函数,整个 ConvertTemperature() 函数只是一个带有嵌套 switch 语句的包装器。我用经典的 ASP 和 PHP 编写,但我想对任何语言开放这个问题。