自我子类责任的用法



我是Pharo的新手,我很难掌握一些概念,特别是subclassResponsibilty

我有以下对象树:

AbstractDictionary
--TreeBasedDictionary (not abstract)
--AbstractArrayDictionary
----SimpleDictionary (not abstract)
----FastDictionary (not abstract)

所有 3 个都实现了at:put:at:(以及更多)的操作。我今天从课堂上了解到,我可以通过以下实现将at:put:拉到AbstractDictionary

at: thisKey put: thisValue
"insert new key / value pair"
^self 
    at: thisKey
    put: thisValue
    duplicate: [self error:'duplicate key']

然后我在 TreeBasedDictionary and AbstractArrayDictionary 中实现了 metod at:put:duplicate:(因为后者的子类的实现是相同的)。然后,当我对一个对象调用at:put:时,它不会在任何一个TreeBasedDictionary , SimpleDictionary or FastDictionary的实例中找到它,但是在查找树时,它会在超类(AbstractDictionary)中找到此方法。然后,这将用at:put:duplicate:调用 self。此方法由上述 3 个类实现,然后指向进行初始调用的类实例的 self 被发送消息以执行at:put:duplicate:

现在,AbstractArrayDictionary,SimpleDictionary and FastDictionary都有一个名为 size 的方法。继承树底部的两个类都实现此方法。 AbstractArrayDictionary按如下方式实现此方法

size
"dictionary size"
self subclassResponsibility 

假设我为我的TreeBasedDictionary实现了这个方法,我想我应该在我的AbstractDictionary类中实现 size 方法,如上所示。

我的问题:为什么我需要这样做,而不是这样:

size
"dictionary size"
^self size

如果是这样,我是否从AbstractArrayDictionary中删除该方法,为什么?

好的,看。

首先,如果您使用

size
  ^ self size

你最终会陷入无限递归。你询问对象sizesize方法询问对象本身size,依此类推。

现在一般关于你应该知道什么。

  1. 您应该避免重复,这就是将类似方法移动到层次结构中的父节点的原因。如果您在所有子类中都有相同的方法,请毫不犹豫地将其移动到超类中。
  2. 您可以在它们应该工作的地方实现方法。 E.i. 根本不用self subclassResponsibility编写方法。对象应响应它们可以理解的消息。AbstractDictionary可以把元素放进去吗?不。那就没有办法了。
  3. 做我在 #2 部分中写的东西并不好。因为
    • 当你浏览AbstractDictionary类时,你会想到它应该支持at:put:duplicate:,但功能取决于实现(又名子类)。
    • 当有人将实现字典的另一个子类时,例如MagicBagDictionary并且忘记实现at:put:duplicate:,那么在执行过程中,他会被温和地提醒这是一个子类的责任,应该实现该方法。否则他会收到一个错误"MagicBagDictionary无法理解的消息"。

再次关于size方法:如果您在某个时候知道在哪里可以获得尺寸 - 那就去做吧。例如,如果 AbstractDictionary 具有实例变量 container 它将容纳所有元素并且应该能够告诉它们的大小 - 您可以实现

size
  ^ container size

抽象词典中。但是,如果您不知道元素将被存储以及如何计算它们的大小,您应该使用:

size
  "dictionary size"
  self subclassResponsibility

这样AbstractDictionary说:

是的,你可以得到我的尺寸,但我不知道如何计算它,因为我不完整。但是我的子类应该知道这一点,所以不要犹豫。

最新更新