均为个人读书笔记,精读并整理出来各个章节的知识点。
什么是面向对象设计?
常见的回答是数据与函数的组合,我在很久以前写过对象的理解,对象的本质与延迟绑定,该文显然只描述了对象的结构是什么,但是却没有对面向对象设计做深入了解学习。
数据与函数的组合,暗示了o.f()
与f(o)
之间是有区别的,但这显然不是事实。面向对象理论是1966年提出来的,但是将数据结构作为函数的参数来进行传递,这件事情远在1966
年以前就发生了。
这里不是很好理解,显然,o.f()
表示的是面向对象的调用方式,f()
函数可能会改变o
对象中的属性值。而f(o)
,即是将数据结构作为f函数
的参数,由f函数
,去改变o对象
这个数据结构的属性值。也就是说在作者看来,这是没有区别的。
另一种说法是,面向对象编程是一种对真实世界进行建模的方式,这种回答是避重就轻的,因为它无法回答对真实世界建模该如何进行,为何要如此做。
还有人回答时会搬出一些名词,如封装
,继承
,多态
。隐含的意思是面向对象编程是这三项的有机组合,面向对象编程语言必须支持这三个特性。接下来会逐一分析这三个概念。
封装体现在对象中的函数和成员变量可见性上,如公有函数和私有成员变量。
但是,这个特性并不是面向对象编程所独有的!C语言
也支持完整的封装,可以使其结构体中部分函数对外部程序调用。反而是C++
作为一门面向对象语言,破坏了C语言
的完美封装性,即不完美的封装,但还是保有一定的封装性。
由于各种原因,我们很难说,强封装是面向对象编程的重要条件,事实上有很多面向对象编程语言对封装性没有强制性的要求。如Python
,JavaScript
等。
继承体现在我们可以用一个对象中继承一部分属性或方法,也可以覆盖掉一部分属性和方法。
既然面向对象编程语言没有提供更好的封装性,那在继承性发面又如何呢?其实也很一般。因为早在面向对象语言发明之前,C程序员
就已经在做类似的工作了,当时是以一种取巧的方式实现这个特性的,将某种数据结构伪装成另外一种数据结构的特性。
所以可以认为,面向对象在编程在继承方面并没有做出什么创新,但还是提供了一些便利,比如不用再取巧伪装特性了。也就是说,面向对象编程中的继承性,还是有点用的,但没有本质上的变化。
在面向对象语言发明之前,就已经有多态性
体现在当时的程序中了。如在UNIX
操作系统中,强制要求每个IO
设备提供5
个标准函数,open
,close
,read
,write
,seek
。IO
驱动程序就会提供这5
个函数的实现。现在要读取一样东西,系统就会调用STDIN->read
,那STDIN
是什么呢?指的是哪个设备呢?它是FILE
类型,相当于IO
驱动程序要实现STDIN
这个接口。这时STDIN
只需要指向FILE
数据结构体中的read
函数指针,就可以完成read
调用了。也就是说STDIN
依赖于具体的FILE
类型。
这正是多态
的基础,归根结底,多态
不过是函数指针的一种应用,从冯诺依曼架构诞生那天起,程序员就在使用函数指针模拟如今的多态
特性了。所以面向对象编程依然没有提出任何新的概念。
用函数指针实现多态最大的问题是它很危险,面向对象编程语言让其变得安全和便于使用了。
多态
的优势在于,它分离了程序和具体实现,相当于使用接口来进行调用,而不是创建一个对象这个具体实现来进行调用,提供了极大的灵活性。
在没有安全的多态
出现前,函数调用是一层依赖一层,底层函数必须要对高层函数可见,高层才能调用到底层函数,高层不可避免地要依赖下层,无论是源代码还是控制流。
这样,系统功能决定了控制流(层级调用控制),而控制流决定了源代码依赖关系。别无选择。
但是一旦使用了多态
,情况就变得不一样了,因为有接口,源代码不再依赖于具体实现,而是依赖接口,控制流再也决定不了源代码的依赖了,具体实现可以随意变换了。
依赖反转,不仅解决了强依赖,从解除依赖后还可以获得独立部署的能力。
例如用户界面->业务逻辑->数据库。我们可以将这三者独立部署,通过接口进行依赖的隔离,让用户界面和数据库成为业务逻辑的插件,因为用户界面和数据库是多变的,业务逻辑一般不会变,使用接口,如果用户界面变了,不用整体打包编译,只需要重新编译用户界面即可,而不需要更改其他的组件。
可以看出来,面向对象编程就是以多态
的手段来对源码中的依赖关系进行控制的能力,这种能力可以构建出插件式的架构,使其各部分能够独立开发和部署。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。