【问题标题】:Why NSMutableString inherits from NSString but not the other way around? [closed]为什么 NSMutableString 继承自 NSString 而不是相反? [关闭]
【发布时间】:2012-09-21 11:08:09
【问题描述】:

NSMutableString 继承自 NSString,但是

  1. 继承是一种“是”关系。所以猫“是”动物。但是NSMutableString“不是”NSString。 (因为NSString不能变异(不能改变))

  2. 通常,子类能做什么,那么基类应该能做什么。比如鱼会游泳,有些动物会游泳。但是NSMutableString 可以改变,而NSString 根本不能改变 - 没有任何NSString 可以改变。

那么为什么NSMutableString 继承自NSString?此外,NSMutableArray 继承自 NSArrayNSString 不应该继承自 NSMutableArray instead,而是将“不更改标志”设置为 YES 吗?这背后的原理是什么?

更新: 一些答案会说:NSMutableString 可以做所有NSString 可以做的事情,因此NSMutableString 继承自NSString。但是这个原理能用吗?石头可以静止不动。猫可以静止不动,也可以移动。猫可以做石头能做的所有事情,但我们不能让猫继承石头,对吧?

如果我有两个游戏对象类:一个是弹性对象,一个是非弹性对象,我认为将弹性对象实现为基类是有意义的,并且非弹性对象从它继承并带有标志外界不能改变。

【问题讨论】:

  • #1:猫是一种动物,但不是所有的动物都是猫,对于#2,子类不仅改进或重新定义基类的现有行为,而且最有用的是扩展基类提供附加功能的类。
  • 其实你只是在兜圈子?你也可以说,一切都是由基本的夸克、胶子、电子和著名的高胸组成的。这些知识是否会导致您假设这些是编程中应该存在的唯一对象?一只死猫的化石可能躺在一颗行星上,它的太阳变成了超新星,所以这只猫被粉碎并吹向宇宙,在那里它的原子可能成为新恒星或其他星际物体的一部分。猫是哺乳动物是动物,这是一个重要的知识吗?
  • 我投票决定将此作为题外话结束。看起来 OP 想要讨论他认为什么是可变/不可变对象的正确继承图。这里不适合这种讨论。
  • 回答你问题的一切都已经说了。另外,你会被提示 Liskov Substitution Principle、duck typing 和 obj-c 协议。我认为没有必要进一步讨论。
  • @vikingosegundo 这些也是很好的解决方案。我认为我们都试图理解的一点是继承不是一些空洞的概念,而是需要与它所应用的问题域有某种关系。比我聪明的人花了很多时间思考这些事情。

标签: objective-c ios cocoa-touch oop


【解决方案1】:

继承是一种“是”关系。所以猫“是”动物。但是 NSMutableString “不是” NSString

错了。 NSMutableString 一个 NSString 因为它可以做任何 NSString 可以做的事情。

通常,子类能做什么,那么基类应该能做什么

也错了。这是相反的方式。而是“基类能做的,子类也能做”。

NSString 不应该从 NSMutableArray 继承吗?

我什至看不到两者之间的关系(只要wchar_t 不是有效的Objective-C 对象)。

总而言之:原因是 NSMutableString 比 NSString 能做更多的事情,并且可以做任何 NSString 能做的事情,因此继承的方向。

【讨论】:

  • 你说 NSMutableString 可以做任何 NSString 可以做的事情。 NSString 可以保持字符串的完整性,并且无论如何都不会改变。 NSMutableString 能做到吗?
  • @JeremyL 将其读作“响应 NSString 响应的所有消息”。请停止无知。 (顺便说一句,从技术上讲,它可以 - NSCFString,它支持 NSMutableString继承自 NSMutableString,但是当从 NSString 实例化时,它会抛出一个异常,说“错误:发送到不可变实例的变异消息”-从中可以推断出它响应变异消息(因为没有“无法识别的选择器”错误),它只是根据其他条件实现其 elsely... )
  • @JeremyL,你怎么了? H2CO3 试图教你面向对象编程 (oop) 的基本知识,它是所有基于类的 oop 的基础。没有必要像你刚才那样做出反应。
  • 阅读原始问题中的更新。我不认为你可以说一个类可以做另一个类可以做的所有事情,所以第一个类应该从第二个继承。
  • @JeremyL 看,当有人不知道或不理解某事时,我不会称之为无知(因为没关系)。你的无知是 1. 你以为我想通过说错什么来冒犯你,你还认为继承规则是主观的(事实并非如此)。 2. 你歪曲了我的话——我确定你知道我所说的“NSMutableString 可以做任何 NSString 可以做的事情”的意思,但你继续为措辞争论不休。
【解决方案2】:

可变版本为不可变版本添加了额外的功能,这就是它们从另一个版本继承的原因。

但是您缺少的另一个原因是具有可变/不可变版本的类实际上是 class cluster 的成员,它隐藏了很多实现。因此,您认为的简单类继承远不止于此。

继承还允许应用Liskov Substitution Principle的便捷方法

【讨论】:

  • +1 用于命名 LSP。我刚回来将其添加到我的答案中,但在这里找到了链接。
  • 不幸的是,我认为可变类型继承不可变类型这一事实违反了 LSP。 IE。 NSMutableString 具有与 NSString 不同的行为,因为它可以被外部代码修改。 NSString 的一个理想属性是它是不可变的。
【解决方案3】:

子类类关系通常被称为“is-a”关系。但实际上我认为 Java 的 extends 更好地描述了它:子类扩展了它的基类的功能。

NSString 对象知道如何保存字符串以及编码。
NSMutableString 对象知道所有这些,但还知道如何更改存储的字符串,因此说“NSMutableString 扩展 NSString”非常有意义

来自一条评论:

基类应该更广泛和通用。一个动物更宽泛、更笼统,就像可变字符串更宽泛、更笼统一样。不可变的字符串更“特殊”。所以这就是为什么以这种方式看待它,基本情况应该是可变的情况是有道理的

NSString 更通用,因为它让您有机会创建它的另一个子类,可以添加更改功能,而无需使用 NSMutableString 的实现,为什么您会想要这样做。如果将功能放置在 NSString 本身中,您将只添加第二次,并且您的对象将携带代码,这是重复的,这将导致代码膨胀。还有很多情况下,您的字符串永远不会改变,即按钮上的标签。如果将其实例化为可变对象以及所有突变代码,那将是浪费资源。

如果我有两个游戏对象类:一个是弹性对象,一个是非弹性对象,我认为将弹性对象实现为基类是有意义的,并且非弹性对象从它继承并带有标志外界不能改变。

不,那将是一个弱设计,因为非弹性对象会携带所有用于执行弹性行为的代码。

【讨论】:

  • 但我不认为我们通过考虑存在多少代码来设计类。层次结构本身更为重要。无论如何,子类只是简单地引用了基类的方法,所以不会浪费太多。
  • 正如我刚刚在 H2CO3 下写的答案:你不是在谈论类子类继承。
【解决方案4】:

我认为继承意味着其原有类的扩大和多样性,尤其是功能。哺乳动物通常是陆生动物,但海豚可能生活在海中。可以说,海豚是从哺乳动物那里继承下来的,在海中生活的功能得到了扩展。

【讨论】:

  • 但奇怪的是,如果我的类可以处理字符串但它绝对不可更改,现在,我“扩展”它,现在它变成了可更改的。
  • 为什么会很奇怪? NSMutableString 可以做任何事情 NSString 可以。此外,它将类扩展为可变的。
  • 这正是继承的用途。现代人类从他们的祖先那里继承下来,并且可以做的远远超过他们(比如说编程)。这就是继承的本质,也可能是进化的本质。
【解决方案5】:

说继承是一种“是一种”关系是正确的,但完全是误导性的。英文中的“is a”意味着“to be”的完整含义。在继承的情况下,“is a”仅暗示子类型关系(最好对类进行编码以满足更强的 Liskov 替换原则要求)。

更好的英语术语(仍然不完美,但更好)是“X 做了 Y 所做的一切”。更好的是,在典型的 OO 术语中,它的意思是“X 拥有 Y 拥有的所有成员”。

NSMutable* 确实是NS* 的子类型,而不是相反,因为NS* 的任何(本质上非变异)消息和属性也适用于NSMutable*,而任何变异消息或可变属性后者不适用于前者。

通常情况下,子类能做什么,那么基类应该能做什么。不正确。事实上,情况恰恰相反。基类能做的,派生类也应该能做。

对于字符串和数组,在 Objective-C 中,数组和字符串有非常不同的方法集。只需检查类文档。因此,它们在继承层次结构中完全分离(当然除了常见的NSObject)。

关于石头和猫的例子,石头的唯一特征是它静止不动,而猫的唯一特征是它静止不动或它可以移动,对于这些属性的适当定义,让猫从石头继承是非常有意义的。

【讨论】:

  • 所以如果我们确实使用里氏替换原则,那么我们实际上会定义一个Square类,然后扩展它来创建一个Rectangle的子类?
  • 类层次结构直接暗示的只是子类型(我将编辑我的答案以澄清这一点)。但实际上仅在遵守 Liskov 的最严格要求时才使用它是一种很好的做法。至于矩形和正方形是否通过子类型相关以及 Liskov 的更强要求是否有效,取决于您附加到矩形和正方形的语义(包括,例如,它们是否是可变的)。很可能它们根本不相关。
猜你喜欢
  • 2018-02-10
  • 2011-10-03
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 1970-01-01
  • 2012-07-01
  • 2015-08-07
相关资源
最近更新 更多