- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我正在修补类中的一个方法,我如何从覆盖方法调用覆盖方法? IE。有点像 super
例如。
class Foo
def bar()
"Hello"
end
end
class Foo
def bar()
super() + " World"
end
end
>> Foo.new.bar == "Hello World"
最佳答案
编辑 : 自从我最初写这个答案已经 9 年了,它值得做一些整容手术来保持它的最新状态。
可以看到编辑前的最后一个版本here .
您不能通过名称或关键字调用被覆盖的方法。这就是为什么应该避免猴子补丁而首选继承的众多原因之一,因为显然您可以调用被覆盖的方法。
避免猴子补丁
遗产
所以,如果可能的话,你应该更喜欢这样的事情:
class Foo
def bar
'Hello'
end
end
class ExtendedFoo < Foo
def bar
super + ' World'
end
end
ExtendedFoo.new.bar # => 'Hello World'
Foo
的创建,这是有效的对象。只需更改创建
Foo
的每个位置改为创建
ExtendedFoo
.如果您使用
Dependency Injection Design Pattern,效果会更好。 ,
Factory Method Design Pattern ,
Abstract Factory Design Pattern或类似的东西,因为在这种情况下,只有你需要改变的地方。
Foo
的创建对象,例如因为它们是由不受您控制的框架创建的(例如
ruby-on-rails),那么您可以使用
Wrapper Design Pattern :
require 'delegate'
class Foo
def bar
'Hello'
end
end
class WrappedFoo < DelegateClass(Foo)
def initialize(wrapped_foo)
super
end
def bar
super + ' World'
end
end
foo = Foo.new # this is not actually in your code, it comes from somewhere else
wrapped_foo = WrappedFoo.new(foo) # this is under your control
wrapped_foo.bar # => 'Hello World'
Foo
对象进入您的代码,您将其包装到另一个对象中,然后在代码中的其他任何地方使用该对象而不是原始对象。
Object#DelegateClass
来自
delegate
的辅助方法标准库中的库。
Module#prepend
: Mixin 前置
Module#prepend
被添加以或多或少地支持这个用例。
Module#prepend
与
Module#include
做同样的事情,除了它直接在类下面的 mixin 中混合:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
prepend FooExtensions
end
Foo.new.bar # => 'Hello World'
Module#prepend
在这个问题中:
Ruby module prepend vs derivation
include
使用 mixin 而不是
prepend
这样做:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
include FooExtensions
end
super
.然而,
Module#include
在继承层次结构中的类上方插入 mixin,这意味着
FooExtensions#bar
永远不会被调用(如果被调用,
super
实际上不会引用
Foo#bar
而是引用不存在的
Object#bar
),因为
Foo#bar
总会先被发现。
bar
方法,而不实际保留实际方法?答案在于函数式编程,正如它经常做的那样。我们将方法作为一个实际对象来持有,并且我们使用一个闭包(即一个块)来确保我们并且只有我们持有该对象:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
old_bar
只是一个局部变量,它会在类体的末尾超出范围,并且不可能从任何地方访问它,即使使用反射!从
Module#define_method
接受一个块,并且块在它们周围的词法环境上关闭(这就是我们在这里使用
define_method
而不是
def
的原因),它(并且只有它)仍然可以访问
old_bar
,即使它已经超出范围。
old_bar = instance_method(:bar)
bar
方法转化为
UnboundMethod
方法对象并将其分配给局部变量
old_bar
.这意味着,我们现在有办法坚持
bar
即使在它被覆盖之后。
old_bar.bind(self)
self
。在 ruby 。换句话说:一个方法总是知道它被调用的对象是什么,它知道它的
self
是。但是,我们直接从一个类中获取方法,它怎么知道它的
self
是?
bind
我们的
UnboundMethod
首先到一个对象,这将返回一个
Method
然后我们可以调用的对象。 (
UnboundMethod
不能被调用,因为他们不知道他们的
self
不知道该怎么做。)
bind
它到?我们只是
bind
对我们自己来说,这样它的行为就会和原来的完全一样
bar
将有!
Method
这是从
bind
返回的.在 Ruby 1.9 中,有一些漂亮的新语法(
.()
),但如果你在 1.8 上,你可以简单地使用
call
方法;就是这样
.()
无论如何都会被翻译成。
alias_method
链
class Foo
def bar
'Hello'
end
end
class Foo
alias_method :old_bar, :bar
def bar
old_bar + ' World'
end
end
Foo.new.bar # => 'Hello World'
Foo.new.old_bar # => 'Hello'
old_bar
污染了命名空间。方法。这个方法会出现在我们的文档中,它会出现在我们 IDE 的代码完成中,它会在反射期间出现。此外,它仍然可以调用,但大概是我们猴子修补了它,因为我们首先不喜欢它的行为,所以我们可能不希望其他人调用它。
Module#alias_method_chain
流行起来。 .
Module#prepend
来演示它上面的例子:
class Foo
def bar
'Hello'
end
end
module ExtendedFoo
module FooExtensions
def bar
super + ' World'
end
end
refine Foo do
prepend FooExtensions
end
end
Foo.new.bar # => 'Hello'
# We haven’t activated our Refinement yet!
using ExtendedFoo
# Activate our Refinement
Foo.new.bar # => 'Hello World'
# There it is!
Module#prepend
,您可能偶尔会在较早的讨论中看到多种不同的想法。所有这些都归入
Module#prepend
.
class Foo
def bar:before
# will always run before bar, when bar is called
end
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
bar
的执行方法。
bar
bar:after
内的返回值.也许我们可以(ab)使用
super
关键词?
class Foo
def bar
'Hello'
end
end
class Foo
def bar:after
super + ' World'
end
end
prepend
使用调用
super
的覆盖方法创建 mixin在方法的最后。同样,after 组合子等价于
prepend
使用调用
super
的覆盖方法创建 mixin在方法的最开始。
super
之前和之后做一些事情,您可以拨打
super
多次,同时检索和操作
super
的返回值,使得
prepend
比方法组合器更强大。
class Foo
def bar:before
# will always run before bar, when bar is called
end
end
# is the same as
module BarBefore
def bar
# will always run before bar, when bar is called
super
end
end
class Foo
prepend BarBefore
end
class Foo
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
# is the same as
class BarAfter
def bar
original_return_value = super
# will always run after bar, when bar is called
# has access to and can change bar’s return value
end
end
class Foo
prepend BarAfter
end
old
关键词
super
的新关键字,它允许您以相同的方式调用被覆盖的方法
super
让你调用重写的方法:
class Foo
def bar
'Hello'
end
end
class Foo
def bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
old
的方法,您将无法再调用它!
super
在
prepend
中的覆盖方法中ed mixin 与
old
基本相同在这个提议中。
redef
关键词
def
单独,我们添加了一个新的关键字来重新定义方法。这是向后兼容的,因为目前的语法无论如何都是非法的:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
super
的含义。内
redef
:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
super + ' World'
end
end
Foo.new.bar # => 'Hello World'
redef
在一个方法中等效于覆盖一个
prepend
中的方法ed混合。
super
在覆盖方法中的行为类似于
super
或
old
在这个提议中。
关于ruby - 当猴子修补实例方法时,您可以从新实现中调用覆盖的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4470108/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!