【问题标题】:Name for over-generalizing a function? Is this an anti-pattern?过度概括函数的名称?这是反模式吗?
【发布时间】:2009-09-30 14:13:24
【问题描述】:

将参数传递给函数以选择函数的功能的名称是什么?

例如:

enum {
   DoSomething,
   ...
};
void f(FunctionType a);

f(DoSomething);
....
f(DoSomethingElse);

对比:

void DoSomething();
....
void DoSomethingElse();

【问题讨论】:

  • 你用什么语言举例?枚举不应该有“FunctionType”的名字吗?
  • 我猜这并不是真正的代码。添加了与语言无关的标签

标签: language-agnostic anti-patterns


【解决方案1】:

一般来说,可以将其视为一种反模式,因为单独的方法更简单、更明确。但是,某些情况可能会改变这种看法。两个例子:

前置控制器

所有Front Controller 模式都是这样工作的(Struts 或更高版本):调用一个带有参数的集中式方法;它稍后被分派给正确的处理程序(由参数之一标识)。这里的重点是在许多特定代码之前(和之后,可能用于例外)应用一个通用代码。

问题不在于执行这种类型的代码,而在于将其包含在您自己的代码中。如果它在框架代码中(已经编写,经过良好测试等),那很好。 例子都是拦截技术,比如 Spring ..

命令

Command 模式可能非常接近:

  1. 标识符可以识别要执行的命令;
  2. 然后您找到正确的代码:在命令模式中,它是一个对象,因此您可以使用映射找到与标识符对应的对象
  3. 执行代码:在Command模式中,所有这些对象都有一个共同的方法,所以调用它是通用的,不需要切换。

【讨论】:

    【解决方案2】:

    像这样的构造通常与遍历所有值的循环一起出现。在那种情况下,它是一个伪装的loop-switch pattern

    但这本身并不是一种反模式。如果您事先不知道参数,这样的设计可能是有效的。

    【讨论】:

      【解决方案3】:

      我已将您传入的参数称为“动作”或“动词”。我还没有看到这个命名为模式。你没有展示的是不可避免的switch 声明,这就是——我假设——为什么你称它为反模式。

      您可以认为它是 command pattern 的错误实现。维基百科有一篇关于 function objects 的文章,这也是一个糟糕的实现。

      在面向对象的语言盛行之前,我们用这样的方式将函数分组到对象中,通常称之为“调度”。 (这个名字已经被包含在模式世界里了。)

      【讨论】:

        【解决方案4】:

        控制耦合

        我是在 Jim Weirich 的演讲中听说的。通常,该方法将具有一个“标志”参数,用于控制要使用的算法。

        Grand Unified Theory of Software Design查看我的笔记(附有一些参考资料)。

        【讨论】:

          【解决方案5】:

          它不一定是反模式!

          即使 f() 函数是一个大开关,它也可以是处理特定“语言”的单个“标记/动词/指令/原子”(或者更确切地说是“发送处理”)的方便位置。此外,f() 函数还可以引入逻辑来决定如何根据运行时上下文调度特定动词。这种以简单、集中的方式将文本/数据动词后期绑定到特定方法的能力很重要,即使在其他情况下,使用 OO 语言的多态和内省特性来服务于该目的可能更合适。

          编辑:请参阅 KLE 的回应,因为它呼应了这是一种模式的想法。 KLE 还提供了对相同/相似的 Command 和 Front Controller 模式的参考。

          【讨论】:

            【解决方案6】:

            这将是重构的目标,通过为每种情况创建单独的方法名称并将任何通用代码放入常用方法中。

            【讨论】:

              【解决方案7】:

              我将其称为 Dispatcher,因为它可能会根据参数调用更具体的代码。

              过于笼统的功能可能是不好的:难以使用、难以维护、难以调试。它们过于笼统的性质使得很难断言前置条件和后置条件以及不变量。尽管如此,Dispatchers 确实有其偶尔的用途。这是提供可扩展性的一种方式——有时它是一种比传统模式更实用的方式。

              【讨论】:

                【解决方案8】:

                这个例子可以被认为是Premature Generalization

                额外参数。 只有一种情况是添加参数 构成函数或类体的泛化:如果这 参数是“活动的”(作为对象或类型或函数指针) 以及函数或类如何工作的一些特殊细节移至 此参数表示的代码。示例是排序 排序函数和分配器的顺序谓词参数 容器类模板或构造函数的参数。额外的 参数可以构成调用 仅当此代码不关心 该参数的实际值。

                代码

                  enum command{ start, stop };
                  void f_command(command do){
                    if( do==start )
                        f_start();
                    else
                        f_stop();
                  }
                  void f(){
                    f_command(start);
                    f_command(stop);
                  }
                

                对比

                  void f(){
                    f_start();
                    f_stop();
                  }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-03-11
                  • 2010-09-09
                  • 1970-01-01
                  • 2011-01-28
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多