何谓猴子补丁(Monkey Patch)?在动态语言中,不修改源代码而对功能进行追加和变更。
使用猴子补丁的目的:
1、追加功能
2、功能变更
3、修正程序错误
4、增加钩子,在执行某个方法的同时执行一些其他的处理,如打印日志,实现AOP等,
5、缓存,在计算量很大,结算之后的结果可以反复使用的情况下,在一次计算完成之后,对方法进行替换可以提高处理速度。
Ruby的类都是开放类,即在类定义之后还可以任意添加内容, 这就使得在Ruby中使用猴子补丁变得特别容易了。另外,Ruby还提供了对方法、类和模块的进行操作的功能,让我们使用猴子补丁更加得心应手。Ruby提供的基本功能如下:
alias:给方法另起别名
include:引入其他模块的方法
remove_method: 取消本类中的方法
undef:取消方法
在 Ruby 中使用 Monkey Patch
我当时遇到的场景是这样的:
我司使用第三方库 fog 进行 EC2 的操作。创建实例等很多命令都需要设置实例类型这个参数。在 fog 里,EC2 的所有类型都定义在 fog/aws/models/compute/flavors.rb 的 FLAVORS 数组里。如果设置的类型不在 FLAVORS 数组里,fog 都会视作是无效的参数而报错。
后来,亚马逊发布了新的html" target="_blank">实例类型 D2。虽然 Ruby 的第三方社区非常活跃,但是 fog 的开发社区还是没有及时添加 D2 到 flavors.rb 里;而我司的工作又迫切需要使用 D2 类型的实例。
背景交待完毕,接下来看看有什么样的解决方法。
方法一:我们可以向 fog 提交一个 Pull Request 来添加新类型。
但是这个方法行不通。我们使用的 knife-ec2 对 fog 的版本依赖必须是 1.25.*,但是 fog 已经更新到了 1.31.0,而且 fog 从 1.27.0 开始结构上有很大的变化。显然,我们不可能再等 knife-ec2 升级支持新版本的 fog,所以我们提交 Pull Request 更新 fog 不能解决问题。
方法二:手动更新旧版 fog 既然不能使用最新版的 fog,我们可以手动编辑 1.25 版的 fog,再打包成 Gem 使用。这个方法比前一个方法更容易操作,但是带来的问题时不易于维护。为了一个极小的改动,把自己的代码加入到第三方库中总是让人觉得不够「干净」。
最后,在同事的指点下,我采用了第三种方法,即 Monkey Patch。我在我司的 Ruby 项目里添加了一个文件 lib/PROJECT_NAME/monkey_patches/flavors.rb,接着在文件中添加以下代码来修改 fog/aws/models/compute/flavors:
require 'fog/aws/models/compute/flavors' class Object def redef_without_warning(const, value) mod = self.is_a?(Module) ? self : self.class mod.send(:remove_const, const) if mod.const_defined?(const) mod.const_set(const, value) end end module Fog module Compute class AWS NEW_FLAVORS = FLAVORS + [ { :id => "d2.xlarge", ... }, { :id => "d2.2xlarge", ... }, { :id => "d2.4xlarge", ... }, { :id => "d2.8xlarge", ... } ] redef_without_warning :FLAVORS, NEW_FLAVORS end end end
总结
通过在自己的代码中添加一个 Monkey patch,我们成功地实现了向 fog 中动态添加新实例类型。我司终于可以使用 fog 创建 D2 类型的机器了;而且这个方法改动的代码量最小,也更加容易维护。
Monkey Patch 并非是完美的解决方法,它会引入一些陷阱。所以这个技巧在软件工程领域还有一些争议。不过,我还是觉得 Monkey Patch 是一个不错的零时性解决方法。
问题内容: 猴子如何修补的功能。我正在尝试添加一个从页面发出的每个ajax请求返回时将被调用的函数。 我知道这听起来像一个可怕的主意,但是用例非常特殊。我想将特定的SDK与控制台(jqconsole)一起使用,但在不修改外部SDK的情况下显示控制台内ajax调用的状态和结果。 我看过这篇文章,它提供了很好的信息,但是没有任何关于猴子修补回调的内容,这似乎超出了我的JavaScript技能。 PS无
问题内容: 我有一个类,位于一个单独的模块中,无法更改。 除了此文件之外,这不会更改MyClass的其他任何位置。但是,如果我添加这样的方法 这将起作用,并且foo方法将在其他任何地方都可用。 如何完全替换班级? 问题答案:
本文向大家介绍Ruby使用Monkey Patch猴子补丁方式进行程序开发的示例,包括了Ruby使用Monkey Patch猴子补丁方式进行程序开发的示例的使用技巧和注意事项,需要的朋友参考一下 猴子补丁(Monkey Patch)是一种特殊的编程技巧。Monkey patch 可以用来在运行时动态地修改(扩展)类或模块。我们可以通过添加 Monkey Patch 来修改不满足自己需求的第三方库,
本文向大家介绍python 猴子补丁(monkey patch),包括了python 猴子补丁(monkey patch)的使用技巧和注意事项,需要的朋友参考一下 写了一段时间java切回写python偶尔会出现一些小麻烦,比如:在java中自定义对象变成json串很简单,调用一个方法就行,但同样的转换在python中却不太容易实现。在寻找python自定义对象转json串的过程中,接触到了猴子补
问题内容: 即使有可能,我也不想讨论这种方法的优点。我相信答案是“否”。但是也许有人会令我惊讶! 假设您有一个核心小部件类。它有一个方法,该方法返回一个高度。高度太大- 这导致按钮(例如)太大。您可以扩展DefaultWidget来创建自己的NiceWidget,并实现自己的形式以返回更好的大小。 现在,一个库类WindowDisplayFactory以相当复杂的方法实例化DefaultWidge
本文向大家介绍Python猴子补丁Monkey Patch用法实例解析,包括了Python猴子补丁Monkey Patch用法实例解析的使用技巧和注意事项,需要的朋友参考一下 属性在运行时的动态替换,叫做猴子补丁(Monkey Patch)。 为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Patch,杂牌军、游击队,