在桑迪梅茨';在Ruby书中的OO设计中,模块和继承有什么区别?

在桑迪梅茨';在Ruby书中的OO设计中,模块和继承有什么区别?,ruby,Ruby,在第153页,她区分了is-a和的行为差异。继承对应于is-a,而模块对应于的行为类似于。但真正的区别是什么?这两种技术都依赖于通过自动消息委派发送的消息,对吗 在她在“理解角色”一章中使用的示例中,似乎主要的区别在于模块更适合duck类型,并用于使看似不熟悉的实体适合某些角色?角色到底是什么?任何可调度的都需要对模块的接口做出响应,因此可以在任何地方进行替换,在任何地方都需要一个响应该接口的角色 而在继承一章中,Metz似乎只是定义了一个层次结构,而没有同样关注duck类型。以她的bikes为

在第153页,她区分了
is-a
的行为差异。继承对应于
is-a
,而模块对应于
的行为类似于
。但真正的区别是什么?这两种技术都依赖于通过自动消息委派发送的消息,对吗

在她在“理解角色”一章中使用的示例中,似乎主要的区别在于模块更适合duck类型,并用于使看似不熟悉的实体适合某些角色?角色到底是什么?任何可调度的
都需要对模块的接口做出响应,因此可以在任何地方进行替换,在任何地方都需要一个响应该接口的
角色

而在继承一章中,Metz似乎只是定义了一个层次结构,而没有同样关注duck类型。以她的bikes为例,她解决了相关类型的问题,这些类型共享共同的行为,但具有一些专门化的子类

然而,存在共同点。两者仍然将抽象行为提升到共享类或模块中。这两个类仍然具有实现相同接口的子类,该接口可用于duck类型。那么真正的区别是什么呢


模块部分比继承部分更强调ducktyping。这是为什么?

有几个不同之处,但在某些方面,它们的行为是相同的。主要区别在于,模块可以是临时的、混合的和匹配的,而您只能从单个类“继承”。但最终,mix-ins和继承的实现是相同的:模块或类被添加到祖先链中,并用于在响应消息时查找方法。在继承的情况下,您定义的类被添加到祖先链的末尾。模块可以包含在链中的不同位置(通常就在您要扩展的类之前),但一旦它们存在,它们的行为就相同

另一个区别是继承更经常地修改或定义初始化。(虽然可以通过模块实现这一点,但很少看到这种情况)。如果您关心对象的初始状态,您可能希望使用继承

至于duck类型,模块通常被认为类似于具有内置实现的java接口。在java中,由于所有内容都是强类型的,所以必须显式地说明对象是否“嘎嘎”。接口就是这样做的,并且是have的“行为”。模块是ruby中最接近的东西


一般来说,模块因其灵活性而更易于使用,但模块更为抽象,必须比基类具有更大的关注点分离。

我这样看待它。我是一个人,那么作为一个人我是一个人。我的妻子也是一个人,但她是一个女人,但我们都扮演着父母的角色。父母不是男人或女人,而是扮演特定角色的人。因此,定义该行为的代码可以放在一个模块中,并由两个类共享

大多数现代语言都有扩展的概念,在扩展中可以将常见行为添加到现有类中。还有更多的例子,但是Kotlin和Swift都在他们的标准库中使用了这一点,在标准库中,他们通过重用在一个地方定义的代码向许多类添加了常见行为


Java在为接口添加默认实现时也添加了这一概念。

这让我想回去重读这本很棒的书。