如何覆盖另一个包中 class 中的现有选择器

How to override an existing selector in a class in another package

我正在使用 Pharo 5.0。在一些情况下,我在现有的 Pharo class 中发现了一个限制或可能是一个错误( 例如 ,DBXTalk/Garage 或 Regex-Core 中的某些内容) .我希望能够在我自己的项目之外修改 class 中存在的一个或一组选择器,并将其作为我的包的一部分。

我找到了一些关于如何在外部 class 中创建 new 选择器并将其移动到我的包中的说明(例如,如图tutorial)。这很酷。但在某些情况下,我实际上想修改外部 class 中的 existing 选择器,并让我的选择器副本覆盖外部 class 中的选择器,当我用它。我不想修改现有的第 3 方或 Pharo 预提供包。

在 GNU Smalltalk 中,我可以像执行 class 扩展的正常部分那样执行此操作。例如:

Kernel.MatchingRegexResults extend [
    at: anIndex [
        "My updated version of the 'official' Kernel.MatchingRegexResults#at: selector"
        "This is part of my package so overrides the 'official' version"
        ...
    ]

    foo [
        "My new foo selector"
    ]
]

我如何在 Pharo 5.0 中执行此操作?我已经做了很多搜索,但找不到这样做的方法。 "extend" 或 "override" 这两个词没有出现在 Pharo by ExampleDeep Into Pharo 书中。

GNU Smalltalk 语法中的代码

Kernel.MatchingRegexResults extend [
    at: anIndex [
        "method body"
    ]
    foo [
        "My new foo selector"
    ]
]

看起来像这样

!MatchingRegexResults methodsFor: 'protocol'!
at: anIndex 
    "method body"
!
foo
    "My new foo selector"
! !

在可以从文件浏览器归档的 Pharo 变更集中。

但请注意,在这两种情况下,GNU Smalltalk 和 Pharo Smalltalk,您实际上是在替换 class 中方法的原始版本。

在 GNU Smalltalk 中,您可能不习惯保存图像,因此您可能认为扩展语法不会修改原始方法中的原始方法 class。

实际上它就是这么做的。

使用 GNU Smalltalk 时,您每次 运行 gst 时通常都使用相同的旧未修改图像。 这是因为 GNU Smalltalk 中图像的默认位置对于普通用户来说是不可写的。所以 gst 每次读取相同的只读图像,你在内存中用 class 定义和扩展修改它,你修改的图像只在你的程序 运行ning 时暂时存在,并在程序中被丢弃出口。

请注意,除了 Milan Vavra 所写的内容之外,名为 *YourPackage-(something) 的协议中的每个方法都属于包 YourPackage,无论 class 是哪个包属于。至少在 Squeak 中,有一种约定,可以将像这样重写的方法放在 *YourPackage-override 协议中。 Pharo 可能有类似的命名约定。移动到包功能将方法移动到这样的 "starred" 协议。

但是,不鼓励使用此类覆盖,因为您不能让两个包同时为同一方法提供实现。 Monticello 将尝试保留原始方法和覆盖方法(参见 PackageInfo>>isOverrideCategory: 的发件人),但您的覆盖方法仍有可能被其原始包的更新覆盖,或者您将错过对原始方法的更新,可能会破坏东西。

"Right Way"是对原包中的原方法进行重构,使其行为更容易定制。