在相当大的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
这个代码在我们的代码库(不仅仅是初始化器)周围的扩散导致我称之为“凌乱多态”。它经常有效但有时会产生非常令人费解的情况。
我有三个问题。
答案 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语言进行程序化编程。”