在相当大的Ruby应用程序中,我们遇到这样的情况:给定的对象由两件事来标识:例如name和id。这些值类型中的每一个都有不同的用途,因此并不完全等效(id和name保留在不同的位置)。因此,我们在应用程序周围传递了各种值(id,名称和对象)。这种情况至少在某种程度上似乎是个问题,因为我们已经被一些bug所困扰,这些bug涉及不清楚应将哪种类型传递给给定的函数。实际上,我回想起多年来在许多应用程序中看到过类似的问题代码,尽管我再也没有给它起任何具体的名字。
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
此代码在我们的代码库(不仅是初始化程序)中的泛滥导致了我所说的“困惑多态”。它通常可以工作,但有时会造成非常令人困惑的情况。
我对此有三个问题。
反模式? “凌乱的界面?”,“凌乱的多态性?”或者是其他东西?
这?我们面临的挑战
普通重构,我们创建的许多测试都使用此方法
松散类型,因此我们必须同时更改两者
测试和实现
同时进行,因此不会具有基于普通测试的脚手架效果
重构。我认为实际上可以“加强”这种松散的多态性,
然后将代码提取到一个函数中,而不是立即将其提取出来。但是会
这是个好主意吗?
最佳答案
您是否不能定义某种get_id方法,以便id返回自身,对象返回id,并且名称执行获取ID所需的所有操作?然后,您总是可以规范化您知道将成为三者之一的任何事物。同样,如果需要,则使用get_name和get_object方法。
也就是说,您已经定义了一个隐式ThingWhatHasAnID接口(interface),并使其成为函数参数的鸭子类型。
除非我丢失了某些东西,否则我将这种反模式称为“缺少创建抽象的机会”。