【问题标题】:Dealing with lots of input parameters, lots of outputs处理大量输入参数,大量输出
【发布时间】:2008-12-08 22:24:46
【问题描述】:

我需要进行复杂的计算。在我的例子中,创建一个 Calculator 类(使用策略模式抽象)似乎是最自然的。

要执行计算,该类需要接受大约 20 个输入,其中一些是可选的,其中一些可能会在未来发生变化等。一旦调用 Calculate() 方法,大约有 20 个需要输出不同的变量。

有很多方法可以实现。

  • 作为参数传入计算方法的输入
  • 通过计算器属性传入的输入
  • 输入封装到自己的类中,然后传递给Calculate() 方法。
  • Calculate() 返回的输出,封装在一个类中
  • 填充到传递给 Calculate() 方法的参数中的输出
  • 在调用 Calculate() 之后从计算器的公共属性中检索到的输出

所有这些方法都有利有弊。 你会怎么做?

更新: 感谢您的反馈。

此计算器的目的是生成报价。输入是客户地址、利率、目标利润、附加费用、产品 ID 等内容,输出包括报价、实际利润、更多费用等。

我已经创建了 ICalculateInput 和 ICalculateOutput 接口及其具体类,现在系统运行良好。 Calculator 类还继承自 ICalculator 接口(因为所涉及的计算因产品来源公司的不同而有很大差异)。

【问题讨论】:

    标签: parameters oop


    【解决方案1】:

    我会推荐

    • 输入封装到自己的类中,然后传递给Calculate() 方法。
    • Calculate() 返回的输出,封装在一个类中

    仅当您进行多步计算,或者基本计算步骤可能多次完成并且重新填充输入很困难时,在计算器中存储状态才有意义。否则,当您对它进行多线程处理或在代码的不同部分重用同一个对象时,这是一个糟糕的抽象。

    有很多参数很难维护和阅读,如果你需要改变,也很不灵活

    改变参数来生成输出是个坏主意。从调用者的角度来看,他“拥有”的类已通过将其传递给函数而被更改,这一点并不明显。

    【讨论】:

      【解决方案2】:

      大多数人建议使用“参数类”和“结果类”。我同意这种方法,但在我看来,您的参数分为几类。也许您可以为必需参数创建一个参数类,并为可选参数或可选参数组创建一个单独的参数类。这样,您可以根据需要的计算类型创建不同的方法;

      Result calculate(RequiredArgs requiredArgs) {
      ...
      }
      
      Result calculate(RequiredArgs requiredArgs, OptionalArgs optionalArgs) {
      }
      
      Result calculate(RequiredArgs requiredArgs, OptionalArgs optionalArgs, OtherOptionalArgs oOpitonalArgs) {
      }
      

      这将使您的 API 更易于使用。如果您不想为不同的组创建类,您也可以使用 Maps,但这需要计算引擎中的更多验证代码。通常我更喜欢参数类,但必须更多地了解您的特定问题才能做出决定。

      由于线程安全和对象可重用性,我不会将计算结果存储在计算引擎本身中。维护无状态代码要容易得多。

      【讨论】:

        【解决方案3】:

        长参数列表变得繁琐且容易出错。告诉我们更多关于应用程序和环境的信息,但一般来说,传递某个类的对象或使用列表等会很诱人。

        我已经做过的一个相当不错的处理方法是使用复合模式。例如,在 Java 中,您可以创建一个 Parameter 接口,然后创建一个实现 Parameter 的对象列表。

        【讨论】:

          【解决方案4】:

          根据经验,不要创建接受超过 3-4 个单独参数的方法

          在 JavaScript 中你不应该做的事情

          var addUser = function (name,surname, age, add1, add2, telephone) {
              //do something
          };
          

          除了上面的,最好做这样的事情:

          var addUser = function (userDetails) {
              //Do something with userDetails.name etc...
          };
          //Then invoke the function by passing in an object:
          var ud = {name : 'Andreas', surname : 'Grech', age : 20, add1 : 'bla', add2 : 'bla', telephone : 12343}; 
          addUser(ud);
          

          这样你就可以通过按你喜欢的任何顺序输入参数来调用函数而不破坏它,你甚至可以跳过一些

          【讨论】:

            【解决方案5】:

            我同意你的输入和输出应该包含在它们自己的类中。

            如果部分或全部参数是可选的,您可能要考虑的一种可能性是使用Builder pattern 构造输入对象。

            【讨论】:

              【解决方案6】:

              你漏掉了

              • 将输入放入字典中,然后传递给Calculate

              有人想知道为什么一个函数有 20 个输入...似乎过分了。但是,如果您需要它们,并且有些是可选的,并且将来可能通过策略模式更改计算方法,那么传入一组命名变量可能是有意义的。您甚至可以在集合中指定 Strategy 模式,这样 Calculate 方法是完全通用的

              【讨论】:

                【解决方案7】:

                你没有提到语言,但我假设是 c#。 我可能会将它们作为结构(或类)传递并以相同的方式返回输出。

                或者,我会找到一些方法来重构它并简化预期的输入/输出。

                【讨论】:

                  【解决方案8】:

                  就我个人而言,我会创建一个自定义输入和输出结构或类,并预先填充它们,将它们传入,并接收输出结构或类的返回值。

                  【讨论】:

                    【解决方案9】:

                    尝试做 .net 中的数据库提供程序类所做的事情。

                    有一个参数类(具有类型和值属性以及方向,即输入/输出)并有一个参数(参数的集合)作为计算器的属性。

                    有关详细信息,请查看 .net 中用于调用存储过程/函数的 OleDBCommand/SQLCommand 类。

                    【讨论】:

                      【解决方案10】:

                      假设您已经深思熟虑并确定,是的,您确实需要所有这些参数:

                      我很可能会使用命名参数,但我选择的语言 (Perl) 支持与顺序无关的命名参数。如果你没有,那么传入一个对象是下一个最佳选择。必须以特定顺序(命名或不命名)传递超过 2-3 个参数只是自找麻烦。

                      对于输出,如果返回的值不止一个,我很可能会返回一个对象。

                      【讨论】:

                        猜你喜欢
                        • 2017-09-05
                        • 2012-05-06
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-06-20
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-10-06
                        相关资源
                        最近更新 更多