某些语言(如 Ruby 和 JavaScript)具有开放类,允许您修改核心类(如数字、字符串、数组等)的接口(interface)。显然这样做会使熟悉 API 的其他人感到困惑,但有充分的理由这样做吗?假设您要添加到界面而不更改现有行为,否则请避免使用它?
例如,添加一个 Array.map 可能会很好不实现 ECMAScript 第 5 版的 Web 浏览器的实现(如果你不需要所有的 jQuery)。或者您的 Ruby 数组可能受益于使用“注入(inject)”的“求和”便捷方法。只要更改与您的系统隔离(例如,不是您为分发而发布的软件包的一部分),是否有充分的理由不利用此语言功能?
Monkey-patching 与编程工具箱中的许多工具一样,既可以用于善也可以用于恶。问题是,总的来说,这些工具最常用于哪些地方。根据我使用 Ruby 的经验,天平偏重于“邪恶”的一面。
那么猴子修补的“邪恶”用途是什么?好吧,一般来说,猴子修补会让你对重大的、可能无法诊断的冲突敞开大门。我有一个类 A
。我有某种猴子修补模块 MB
可以修补 A
以包含 method1
、method2
和 方法 3
。我有另一个猴子修补模块 MC
,它也修补 A
以包含 method2
、method3
和 方法 4
。现在我进退两难了。我调用 instance_of_A.method2
:调用了谁的方法?答案可能取决于很多因素:
- 我是按照什么顺序引入补丁模块的?
- 补丁是立即应用还是在某种有条件的情况下应用?
- 啊啊啊啊啊!蜘蛛从里面把我的眼球都吃掉了!
好吧,所以#3 可能有点过于戏剧化了......
无论如何,这就是猴子补丁的问题:可怕的冲突问题。鉴于通常支持它的语言的高度动态特性,您已经面临许多潜在的“远距离幽灵般的 Action ”问题;猴子修补只是增加了这些。
如果您是负责任的开发人员,那么可以使用猴子补丁是件好事。不幸的是,IME,往往会发生这样的情况,即有人看到猴子补丁并说,“太棒了!我只是猴子补丁,而不是检查其他机制是否更合适。”这种情况大致类似于人们创建的 Lisp 代码库,他们在考虑将宏作为函数来做之前就接触到了宏。