“凌乱多态”反模式

时间:2009-04-03 00:09:53

标签: ruby refactoring tdd polymorphism anti-patterns

在相当大的Ruby应用程序中,我们遇到一种情况,即给定的对象由几个东西标识:name和id。这些值类型中的每一个都有不同的用途,因此不完全等效(id和name在不同的地方持续存在)。因此,我们将围绕应用程序传递各种值(ID,名称和对象)。这种情况至少在某种程度上似乎是一个问题,因为我们已经被错误所困扰,这些错误涉及不清楚应该将哪种类型传递给给定的函数。我实际上回想起多年来在许多应用程序中看到类似的问题代码,尽管我再也没有给出具体的名称。

Ruby作为一种无类型语言,不像C ++那样允许基于类型的经典多态函数。作为一种解决方案,一位同事经常采用这种代码:

  def initialize starting_value
    if starting_post.kindof? Foo
      @starting_id = get_id_from_foo starting_value
    elsif starting_post.kindof? Bar
      @starting_id = get_id_from_bar starting_value
    else
      raise "illegal type"
    end
  end

这个代码在我们的代码库(不仅仅是初始化器)周围的扩散导致我称之为“凌乱多态”。它经常有效但有时会产生非常令人费解的情况。

我有三个问题。

  • 这是一个正式的名称吗? 反模式? “凌乱的界面?”,“凌乱的多态?”或其他什么?
  • 人们认为这有多糟糕?
  • 有没有系统的重构方法 这个?我们面临的挑战 普通的重构,我们创建的许多测试使用这个 松散打字,因此我们必须改变它们 测试和实现 同时也不会有普通测试的脚手架效应 重构。我认为人们实际上可以“加强”这种松散的多态性, 并将代码抽象出函数而不是立即将其删除。但愿意 这是一个好主意吗?

2 个答案:

答案 0 :(得分:7)

你不能定义某种类型的get_id方法,以便id返回自身,一个对象返回id,并且名称执行它需要做什么来获取id?然后,你总是可以规范任何你知道将成为三者之一的东西。如果需要,也可以使用get_name和get_object方法。

也就是说,你已经定义了一个隐含的ThingWhatHasAnID接口,并将其作为函数参数的duck-type。

除非我遗漏某些东西,否则我会称这种反模式“错失创造抽象的机会”。

答案 1 :(得分:4)

几乎每当你发现自己打开一个对象的类时,就会发现行为应该是对象本身的一种方法。基于接收器的消息调度多态的。在这种情况下,它应该是这样的:

def initialize starting_value
  @starting_id = starting_value.id
end

定义id以执行以前用于执行的各种get_id_from_*方法。非法类型的案例已经提出,因为你会得到一个NoMethodError。

至于这个叫什么,我称之为“用OO语言进行程序化编程。”