在大一初学C语言的时候,所解决的问题都是一些轻量级的简单问题,当时写过一个教学管理系统。这个教学管理系统的功能很简单,思想就是“流水线”:按部就班的实现所有流程。要完成整个教学管理系统,实际上就是完成一些函数,这些函数之间的逻辑组织结构就是人所认知的逻辑结构,要完成一个教学管理系统,首先要实现一些功能:比如 1.录入学生信息 2.为每个学生分配课程 3.为每个学生分配老师 4.为每个学生录入成绩 5.进行成绩的统计。
上面这个流程很直观,而且实现起来也很流畅。我们只需要将这些函数进行实现就行了。但是在实际操作中,这样POP的程序设计过程可能会遇到一些问题,比如某一年,有一些课程可以改由多名教师上课,学生分配的课程可以进行更改,学生可以进行分数复核等等。但凡要实现这些功能,就需要对原有软件实现做出极大的改造,甚至是几乎重写。
而众所周知,现在软件构造讲究“敏捷开发”,什么是敏捷开发呢?
敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。
如果我们仅仅是为了完成课程作业的话,那我们基本用不到版本的更替迭代,问题是如果我们这样做,那实际工程只能是一堆“屎山”,代码几乎无法维护。这不禁让我想到此前的报道,美国的很多银行系统使用的是几十年前流行的语言,这种语言现在已经基本没人用了,而且之前的代码没有现在“敏捷开发”的思想,当时的代码组织结构极其笨重,虽然很稳定,但是难以修改。在几十年后的今天当人们想要加以维护时,发现这件事难以登天,即使开出百万年薪也找不到合适的人。这个例子也说明了软件“易于更改性”的重要性,试想一下,如果所有软件都只追求稳定性而不考虑可更改性,那每隔几年就要进行“轮子重造”,不断的造轮子,会让程序员们苦不堪言。
但是通过OOP的思想,我们就可以解决远古的不具有“面向对象”特性语言的种种缺点。OOP和POP的本质区别在于:他们考虑的事情不同。
POP是面向过程的编程思想,这种思想是“以过程为本”的,类似于状态转移。我们要做一件事,首先要考虑的是要实现哪些步骤,就像上面的教学管理系统,每个步骤只有在上一个步骤完成之后才能进行实现。这是一个“流式”编程的概念,他模仿人们做事的流程,因此单元与单元之间的耦合度很高,只要有一个功能发生变化,可能就会导致其他的功能完全需要重构。
而OOP则是面向对象的编程思想,这种思想是“以人为本”的,我们将实现每个功能都划归给一些特定的对象,比如上面的教学管理系统,我们需要实现的对象可能包括:课程,教师资源,选课系统等等,我们考虑的不是事件与事件之间的耦合关系,我们恰恰是要减少模块之间的关联关系。这也是为了我们进行后期维护而进行的设计,倘若模块之前耦合度极高,那又会陷入面向过程编程的深坑。
在引入OOP之后,我们就自然而然的可以感受到OOP的三大特征:封装性、继承性和多态性。所谓封装性,就是模块与模块之间是互不关联的,也就是他们之间的耦合度比较低,我们可以把模块当做砖头,实现一个软件就是完成一些砖块的堆积。通过封装让开发app就像盖房子一样简单,我们不需要自己造各种砖头,甚至可以复用别人的砖头。
所谓继承性,也是为了简化编程的复杂度,因为自然界有很多的子类和父类的关系,或者说有些物品的所有特征都存在于别的物品中。那我们只需要通过简单的继承,就可以使这些子类完全获得父类可见的成员变量和方法,大大减低了代码量。
说到这里,就不得不提一下Java特殊的继承机制,在C++里面是可以有多继承的,即一个子类可以继承多个父类。但是这样的设计往往会导致代码逻辑之间很混乱。在Java中取消了多继承的功能,我们一般采用接口的多实现来完成C++里面需要多继承才能实现的功能。就像在我们HIT软件构造课程所写的三个app中,对于每个app都可以设定不同的接口组合,我们通过实现多个接口来完成这些功能的组合,显得尤为方便。
最后就是多态性,这个特性存在的原因就是继承,比如方法的多态-重写,子类型多态-通过不同的实例化。
上面就是一些OOP和POP的功能对比,较详细的介绍了一些OOP的优点。