正确理解面向对象程序设计 基础篇(四)为什么要使用面向对象的方式进行程序设计?

  • Post author:
  • Post category:其他


为什么要使用面向对象的方式进行程序设计?



面向过程与面向对象

面向对象编程是后来才出现的,之前的的软件开发方式大多是面向过程的。

面向过程简单的说就是将需求看成是各种问题的解决过程(输入、执行、结果这样的过程)。每个过程中包含1个或多个函数,按照顺序执行。我们的操作系统主要是以面向过程的形式开发出来的。

所以面向对象要解决的并不是软件复杂性的问题(操作系统就很复杂)。

那么面向对象要解决的是什么问题呢?



软件危机

软件起初是由专业的科研人员来用做科研的。随着硬件成本的下降、硬件的性能提升、图形化操作系统的不断完善。软件经历了

实验室→商用→民用

这样的普及发展过程。

每一个阶段软件面对的用户数量及系统复杂程度都有巨大的提升。尤其是后来互联网的兴起更是对软件的安全性、并发性和可用性等方面有越来越高的要求。

软件危机在没有互联网的商用时期出现了。

难以维护升级的软件,混乱错误的软件、无法使用的软件。

软件危机到底是什么呢?

软件的复杂度并不是主因,主因是需求变更。一个高复杂度的软件无法在初期建模阶段就能够覆盖所有的需求(有未知)。随着开发的进行,需求总是在不断的变更当中。软件开发越到后期需求的变更所付出的代价就越大,最后直到大过预算,大过项目整个的开发成本,项目就面临失败(通常情况下项目就终止了)。


需求变更带来的是应对变更的高成本




灵活的应对变更是降低软件开发成本的重要研究课题。

软件工程在努力的从软件开发过程的角度来解决软件危机(应对变更)。

而面向对象的语言,是从编程语言的层面来解决软件危机(应对变更)。

(与操作系统不同,软件常常在应用层面变化。也就是高级语言这个层面产生更多的变化。)



面对需求变更

需求变更带来软件的修改。

除了要完成需求以外,还要保证修改不会影响软件的其它功能的正常运行。

以面向过程为例:

假设原有一个函数A。有30个地方使用函数A,现在有5个地方要变更。那么做法是建立函数B,并且将那5个地方的函数A替换为函数B。(注意这里的函数是可能包含子函数的)

看起来很简单吧。

但是有个不确定的地方

  • 函数B能否完全替换函数A(因为我们只会验证那5个地方)。

哪怕验证了全部30个地方仍然可能有问题,因为函数A可能只被部分使用,函数A的定义和函数B的定义并没有强关联。


注释上写用B不要用A,A不是我做的用A出错我不管。

了解面向对象的同学可能会纳闷,函数不就是方法嘛,方法变更完直接改个名不就完了嘛。是的,这样也没问题。不过,如果第三个开发者来接手项目。他会看到函数A和函数B,他想要知道咋回事除了看注释以外还要读原来的代码。

面向对象的语言刻意很好解决这个问题。通过类的继承,可以在不影响其它任何方面来实现方法的扩展。同过建立接口和抽象类,也可以很方便的对类进行扩展。

你甚至不需要知道原来的实现方法,就可以

确定

自己的修改不会影响原有调用。调用的那一方也不需要改变调用的方法名称也没有方法变更后的学习负担。

有人可能会疑问那我约定好用一样的方法名不就可以了嘛。是的,以前是靠约定来实现这种应对变化的方法。现在是靠语言的支持,强制执行。一个可能需要再确认,一个是不需要确认。面向对象语言应具有更灵活的面对需求变更的处理。(随着面向对象程序设计的发展,现在我们大多数情况下是面对接口开发,因为多数面向对象的语言不支持多继承但是支持多接口实现,这是后话)



封装、继承、多态

封装:程序书写时将一个类定义为由属性和方法组成的代码段,这些属性和方法被装在这个类中。设计者可以选择这些属性和方法是否可以暴露给外界,以及暴露到什么程度。

继承:B类继承A类。B类自动获得A类所有的方法和属性。

多态:类的多态通过继承来完成。类方法的多态可以通过定义不同的参数/返回值有无来定义同名方法。因此,在类中,一个方法名可以对应多种实现。



总结

面向对象的出现是为了方便程序扩展,并通过类与类之间的关系来形成鲜明结构,让除开发者以外的人也能够快速理解类与类之间的关系。



版权声明:本文为TinMan2012原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。