【问题标题】:Best way to write a conversion function编写转换函数的最佳方法
【发布时间】:2008-09-12 14:19:29
【问题描述】:

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

示例 1 - 单独的参数: 函数 convertTemperature("摄氏度", "华氏度", 22)

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

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

想法?

【问题讨论】:

    标签: coding-style


    【解决方案1】:

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

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

    【讨论】:

    • 哈哈......当我开始我的工作时,你的答案想要在这里。你打败了我! :-)
    【解决方案2】:

    取决于语言。

    一般来说,我会在枚举中使用单独的参数。

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

        一些事情:

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

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

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

        【讨论】:

          【解决方案5】:

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

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

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

          【讨论】:

            【解决方案6】:

            在 C#(可能是 Java)中,最好创建一个 Temperature 类,将温度私下存储为 Celcius(或其他),并具有 Celcius、Fahrenheit 和 Kelvin 属性,这些属性可以在 get 和设置语句?

            【讨论】:

              【解决方案7】:

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

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

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

              【讨论】:

              • 您毫无根据地假设您必须使用通用 Units 枚举而不是对目的更有用的东西,例如枚举 TemperatureUnits。
              【解决方案8】:

              我会选择

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

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

              如果您要向用户提供类似于 Google 搜索框的内容,那么使用“c-f”等方便的快捷方式对他们来说是件好事。不过,在下面,我会在外部函数中将“c-f”转换为“celsius”和“fahrenheit”,然后再像上面那样调用 convertTemperature()。

              【讨论】:

                【解决方案9】:

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

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

                【讨论】:

                  【解决方案10】:

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

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

                  【讨论】:

                    【解决方案11】:

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

                    在 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'
                    

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

                    【讨论】:

                      【解决方案12】:

                      顺便说一句,按照问题陈述中的建议,实现三参数版本并不需要更多的工作。

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

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

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

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

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

                      【讨论】:

                        【解决方案13】:

                        类似于@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); }
                            }
                        }
                        

                        【讨论】:

                          【解决方案14】:

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

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

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

                          【讨论】:

                            【解决方案15】:

                            这是我对此的看法(使用 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 标度 - 一个函数来统治它们。 =)

                            【讨论】:

                              【解决方案16】:

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

                              【讨论】:

                                【解决方案17】:

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

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

                                【讨论】:

                                  【解决方案18】:

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

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

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 2011-03-05
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2022-08-17
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多