多重继承不好的观点是错误的 — 小评 松本行弘的程序世界

2023-10-05 13:30

本文主要是介绍多重继承不好的观点是错误的 — 小评 松本行弘的程序世界,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

首先得说, 一般某种语言的发明人写的关于自己语言的东西都是非常值得阅读的, 从别的牛人那里你也许能学会很多奇技淫巧, 但从语言发明人那里你能学到语言发明人本身设计的初衷, 以及设计时的一些抉择. 这种思路是独一无二, 绝无仅有的. 所以我在学习一个新语言时, 假如语言发明人有写书, 一定优先阅读.

语言发明人写的书又分两种, 一种是语言的教材, 这个几乎是惯例, 因为一个语言在初期, 没有其他人会用的时候, 语言发明人不教会别人怎么使用, 那可能就没有人会用了, 而他们这本教材的好坏甚至能决定他们语言最后能有多流行. 我听说一个有意思的言论, 说C语言之所以这样流行, 很重要的原因就是C程序设计语言这本教材实在写的太好了. 虽然有些夸张, 但是不无道理, 这个和现在一些开源库对文档要求很高的道理是一样的, 一个开源库的文档写的好不好, 对这个库最后是不是会被很多人使用有极大的关系. 当然, 也有反例, 鬼知道Anders Hejlsberg是怎么把一本C#的语言的教材C#程序设计语言, 写的就像是语言的规格说明书一样.
另外一种, 那就是除了教材外, 写关于自己语言的设计想法的书, 这种书就更加少了, 就目前而言, 我只看到过Bjarne Stroustrup写的C++语言的设计与演化和这本松本行弘的程序世界. 欢迎大家给我推荐其他的类似书籍. C++语言的设计与演化讲述了BS在设计C++时的各种抉择, 看完该书后, 我第一次明白C++到底是怎么设计成那么难用的, 当然, 同时也明白了怎么使用C++是正确的. 后来还反复的读了好几遍, 工作后, 也极力的推荐给使用C++的同事阅读, 事实上, 现在我买的这本书就还在我原来的同事那里, 虽然我已经离开原公司了. 如果说, 那个时候读C++语言的设计与演化还太无知(我那时候才刚刚参加工作), 并且C++又是我接触编程的第一门语言, 导致碰到一些可能习以为常的东西还如获至珍, 所以才这么喜欢的话, 那松本行弘的程序世界在我工作五年, 已经或多或少学习了不下于10门编程语言后, 仍然能给我很多启发, 就更加值得向大家推荐了.

  • Ruby的继承体系
    • Mix-in
      • Ruby的Stream结构
      • C++的Stream结构
  • 本书不足
  • 额外的声明

Ruby的继承体系

多重继承不好的观点是错误的
– 松本行弘

这是我感觉是全书最精彩的部分, 本文也主要关注这一部分. 特别是对于多重继承部分的描述, 充分体现了一个优秀的程序员, 语言设计者的功底.

讲到这里, 我想先讲讲我对这部分内容的认识历史.
在C++语言的设计与演化中, 我们知道, 多重继承在加入C++之前就有争议, 但是BS坚持自己的意见, 最终C++还是支持了多重继承. 并且为被很多人批评的多重继承进行了辩护, 他的确承认了多重继承可能带来的混乱, 但是认为, 在有的时候, 多重继承的抽象的确是有意义的, 并且这种抽象在有的时候会更加优美. 本着C/C++的设计原则, “程序员总是对的”, 不应该人为的去限制程序员, BS坚持的提供了多重继承这一工具, 并让程序员去决定, 什么时候用会导致混乱, 什么时候用可以让设计更加优美.
在成为标准以后, 多重继承的争议一直没有消失, 各种支持多种继承的语言甚至在怎么解决菱形继承上出现了不同的解决方案. 比如C++中, 菱形继承还引入了一个更扭曲的虚继承, Python支持多种继承, 并且因为所有的对象都继承于共同的基类Object, 导致任何多重继承其实都是菱形继承, 当你真的开始自己用多重继承时, 其实继承结构已经是一张网了, 对此, Guido Van Rossum的答案是用深度优先搜索, 靠基类排列的顺序来决定, 个人觉得不仅没有解决这个问题, 反而显的更加神奇.
而无数的JAVA用户者则是把C++的多重继承当作笑话和C++混乱的根源, 自豪的宣布JAVA没有这个问题. James Gosling给出了他自己的解决方案, 那就是没有没有C++自由的多重继承, 只支持对实现的单继承, 并引入了接口, 只允许接口的多重继承. 并且, 在继承接口和继承基类形式上特别加了一些区别, 所以实际中, 很多人并不把这叫做多重继承, 并宣称JAVA没有多重继承.
有意思的是, 高老头后来去了Google, 而我使用C++时尽量遵循的规范Google C++ Style Guide中就明确的规定了禁止C++的多种继承(不代表这两个事情有任何关系), 并且在Style Guide中自己给出了他们的Interface定义, 只允许使用此Interface进行类似JAVA的接口多重继承. 这真是趣事, 在一个Style Guide中, 去强行修改一个语言特性, 也足以证明C++的多重继承有多么臭名昭著了.

就个人感受, 以前开发的一个iOS游戏项目, 仅仅开发了半年, 就因为代码混乱不堪, bug多到无法维护, 项目一度在另外一个工作室被cancel, 然后我们中途再接手开发, 并且把多重继承看作是混乱的根源, 后来整理代码的很大部分工作就是用组件的方式去替代掉混乱的继承, 并且改善后设计清晰了很多, 再后来, 我开发一个Android项目的时候, 第一次真的在项目中去使用JAVA, 深刻的体会到了JAVA对继承的限制, 也真的去实践了GOF在设计模式中早就提到的”组合优于继承”这一设计原则, 也去体会了JAVA社区提倡的面向接口编程. 事实上, 我也逐渐的感觉到了, 其实, “继承本身就是一种强耦合”, 就是一种子类对父类的依赖耦合, 在一些书籍中提到, 甚至继承本身都是不提倡的, 也就是说, 提倡的是基于对象的设计(OB), 而不是面向对象的设计.(OO)

故事到这里就是我的认识了, 鉴于我的认识都来自于各种上述提到的流行语言和经典书籍, 我想大部分人可能会有和我类似的观点吧. 但是Mats不这么看.

Mix-in

本来只是为了跨越继承层次来共享代码, 现在却需要另外生成一个独立对象, 并且每次方法调用都要转送给那个对象, 这实在是不太合理, 而且执行的效率也不高.

Mats直说JAVA对多重继承的解决方式不够方便, 也不太合理. 他提供的解决方案是, Mix-in.
Mix-in按照以下规则来限制多重继承.
通常的继承用单一继承
第二个以及两个以上的父类必须是Mix-in的抽象类

Mix-in类是具有以下特征的抽象类.
不能单独生成实例
不能继承普通类

通过这种在接口和普通多重继承之间的折衷, Mix-in提供了对实现的多重继承, 同时对其进行了限制, 使得继承结构不会成菱形, 而是和单一继承一样的树型. 在Ruby中, Mix-in是通过模块(module)的概念来实现的. 作为例子, Matx用了Ruby中的Stream实现的例子.

Ruby的Stream结构

Ruby

C++的Stream结构

Cpp

从这点看, 为什么我说这是一种折衷方案呢, 因为相对于只允许接口的多重继承来说, 实现更加方便了, 但是, 对于真正的面向对象来说, 毕竟还是需要把一些实现给拆分成更细粒度的类, 才能符合Mix-in的要求. 比如看上面两个图就能发现, 同样的功能, C++需要的类要比Ruby需要的少. 从这点来说, Mats批评JAVA的组合方式为了共享代码需要生成一个独立对象是不方便的, 而实际上Max-in也会相对真正的多重继承来说需要更多的独立对象, 只是使用的方式不是组合, 而是继承. 当然, 这种限制能带来类似JAVA的更加良好的设计, 避免菱形继承及类似更加复杂的继承体系, 同时, 又比JAVA那种方式更加方便, 大家都知道, 加一个继承只要一个单词, 而加一个对象的组合调用, 往往需要增加N个函数接口, 以及N个调用.(虽然有种东西叫做委托) 有趣的事情是, 在编程这件事情上, 很多时候, 折衷的方法却往往是优秀的方法…

本书不足

  1. 作者在前言里面介绍, 是在杂志上连载的文章的基础上编辑修改来的, 所以有些地方其实能发现明显的重复, 甚至不仅仅是文字内容重复, 连Enumerable的那张表都原封不动的重复了两遍.
  2. 后面的章节趣味性有余, 但是感觉思想性稍微有些弱. 所以我看的时候过的比较快, 不过这也见仁见智吧, 也不排除我对相关内容兴趣不足的因素.

额外的声明

我在最新的文章中把所有关于书的链接从豆瓣改为亚马逊了, 假如你点击我的给的链接过去并且买了书, 亚马逊会给我一些佣金, 当然我知道这没有多少, 但是聊胜于无吧, 以后的文章类似, 不再声明了. 我甚至都不知道这样无害的事情为什么需要声明, 但是好像在中国你需要这样做, 因为别人都这么做了.

writen by  九天雁翎(www.jtianling.com)
           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述

这篇关于多重继承不好的观点是错误的 — 小评 松本行弘的程序世界的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/151300

相关文章

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

Java 继承和多态的作用及好处

《Java继承和多态的作用及好处》文章讲解Java继承与多态的概念、语法及应用,继承通过extends复用父类成员,减少冗余;多态实现方法重写与向上转型,提升灵活性与代码复用性,动态绑定降低圈复杂度... 目录1. 继承1.1 什么是继承1.2 继承的作用和好处1.3 继承的语法1.4 子类访问父类里面的成

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图

如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socket read timed out的问题

《如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socketreadtimedout的问题》:本文主要介绍解决Druid线程... 目录异常信息触发场景找到版本发布更新的说明从版本更新信息可以看到该默认逻辑已经去除总结异常信息触发场景复

Python struct.unpack() 用法及常见错误详解

《Pythonstruct.unpack()用法及常见错误详解》struct.unpack()是Python中用于将二进制数据(字节序列)解析为Python数据类型的函数,通常与struct.pa... 目录一、函数语法二、格式字符串详解三、使用示例示例 1:解析整数和浮点数示例 2:解析字符串示例 3:解

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程