在一些个人项目中,我正在慢慢地从PHP5转向Python,我现在很喜欢这种体验。在选择沿着Python路线前,我看了Ruby。我从红宝石社区注意到的是,猴子修补既常见又备受推崇。我还遇到了一个关于调试ruby s / w的试验的很多的恐怖故事,因为有人包括一个相对无害的库来完成一些工作,但修补了一些使用频繁的核心对象而没有告诉任何人。
我选择Python(除其他原因外)其更清晰的语法以及它可以完成Ruby所能做到的事实。 Python正在使得OO点击比PHP有所改进,我正在越来越多地阅读OO原则以增强这种更好的理解。
今晚我一直在阅读Robert Martin's SOLID原则:
我目前正在 O :软件实体(课程,模块,功能等)应该开放以进行扩展,但需要修改。
我的头脑是在确保OO设计的一致性和整个猴子修补之间的冲突。我知道可以在Python中进行猴子修补。我也明白,“pythonic”是遵循常见的,经过良好测试的oop最佳实践&原理
我想知道的是社群对两个相反主题的看法; 他们如何互操作,当它最好使用一个时,是否应该在所有......希望你能为我解决这个问题。
答案 0 :(得分:29)
猴子修补(覆盖或修改预先存在的方法)与简单添加新方法之间存在差异。我认为后者非常好,前者应该被怀疑地看待,但我仍然赞成保留它。
我遇到过很多问题,其中第三方扩展会对核心库进行monkeypatches并破坏内容,而且它们真的很糟糕。不幸的是,它们总是看起来源于第三方扩展开发人员采取阻力最小的路径,而不是考虑如何正确地构建他们的解决方案。
这很糟糕,但它不再是猴子修补的错,而不是刀具制造者的错误,人们有时会割伤自己。
我见过的唯一合法的猴子补丁需求是解决第三方或核心库中的错误。仅此一点,它是无价之宝,如果他们取消了这项工作的能力,我真的很失望。
我们的C#程序中的错误时间表:
我们的rails程序中的错误时间表:
错误修正过程看起来很相似,除了monkeypatching,它是一个15分钟的解决方案,一个5秒的'提取',而没有它,疼痛和痛苦随之而来。
PS:以下示例是“技术上”monkeypatching,但它是“道德”monkeypatching?我没有改变任何行为 - 这或多或少只是在红宝石中做AOP ......
class SomeClass
alias original_dostuff dostuff
def dostuff
# extra stuff, eg logging, opening a transaction, etc
original_dostuff
end
end
答案 1 :(得分:5)
在我看来,monkeypatching对于拥有可以被滥用的东西很有用。人们倾向于发现它,并且觉得应该在每种情况下使用它,也许混合或其他结构可能更合适。
我不认为这是你应该禁止的事情,这只是Ruby家伙喜欢使用的东西。你可以用Python做类似的事情,但社区已采取的立场应该更简单,更明显。
答案 2 :(得分:4)
猴子补丁不是ruby-explicit,它也是通过javascript完成的,具有负(IMO)效果。
我的个人意见是猴子补丁应该只进行
a)为您需要的新版语言中提供的旧版语言添加功能。
b)当没有其他“合乎逻辑”的地方时。
有许多简单的方法可以使猴子修补非常糟糕,例如能够改变 ADDITION 等基本功能的工作方式。
我的立场是,如果可以避免,请这样做。
如果你能以一种不错的方式避免它,那就是你的荣耀。
如果你无法避免它,请得到200人的意见,因为你可能只是没有考虑到它。
我的宠物讨厌是扩展功能对象的mootools。是的,你可以这样做。而不只是人们只是学习javascript如何工作:
setTimeout(function(){
foo(args);
}, 5000 );
为每个函数对象添加了一个新方法(是的,我不是在开玩笑),所以函数现在有自己的函数。
foo.delay( 5000 , args );
这种废话的附加效果是有效的:
foo.delay.delay( 500, [ 500, args ] );
就像无限的广告一样。
结果呢?你不再拥有一个图书馆和一种语言,你的语言鞠躬到图书馆,如果图书馆恰好在范围内,你就不再拥有一种语言了,你不能按照学习时的方式做事。语言,而不是必须学习一个新的命令子集,只是为了不让它掉在脸上(以过度减速为代价!)
我可以注意到foo.delay还返回了一个对象,它有自己的方法,所以你可以做
x = foo.delay( 500, args );
x.clear();
甚至
x.clear.delay(10);
这可能听起来过于有用,但是你必须考虑到使这个可行的大量开销。
clearTimeout(x);
太难了!
(免责声明:自从我使用moo以来已经有一段时间了,并试图忘记它,并且函数名称/结构可能不正确。这不是API参考。请查看他们的网站了解详细信息(对不起,他们的API参考很糟糕!))
答案 3 :(得分:4)
Mokeypatching通常是错误的。创建一个合适的子类并添加方法。
我在生产代码中使用了一次monkeypatching。
问题是REST使用GET,POST,PUT和DELETE。但是Django测试客户端只提供GET和POST。我已经为PUT(如POST)和DELETE(如GET)进行了monkeypatched方法。
由于Django客户端和Django测试驱动程序之间的紧密绑定,将monkeypatch支持完整的REST测试似乎是最简单的。
答案 4 :(得分:3)
你可能会发现关于Ruby的开放类和开放封闭原则的启发this discussion。
即使我喜欢Ruby,我觉得猴子修补是最后的工具,可以完成任务。在所有条件相同的情况下,我更喜欢使用传统的面向对象技术,并具有多种功能编程优势。
答案 5 :(得分:2)
在我看来,猴子修补是AOP的一种形式。文章Aspect-Oriented Design Principles: Lessons from Object-Oriented Design(PDF)提供了一些关于如何将SOLID和其他OOP原则应用于AOP的想法。
答案 6 :(得分:1)
我的第一个想法是猴子修补违反了OCP,因为班级的客户应该能够期望该班级能够始终如一地工作。
答案 7 :(得分:0)
猴子修补只是简单错误,恕我直言。我没有遇到你之前提到过的开放/封闭原则,但这是我长期坚持的原则,我同意它100%。我认为猴子修补是一种更大规模的代码气味,一种编码哲学气味,就像它一样。