面向对象编程 VS 面向过程编程

7 篇文章 1 订阅
3 篇文章 0 订阅
    对于每个有计算机背景的同学来说C++必定是一个入门级的语言,除此之外我们或多或少的都有接触过Java,Python,Php等等语言,无一例外,他们都是面向对象的编程语言,那么当我们在使用这些语言,使用Class来进行包装我们的代码的时候我们是在进行面向对象编程吗?
    对于这个问题之前并没有去思考过,只是最近有与人讨论面向对象这个问题才开始思考,思来想去也没有办法使用一句话来说明白到底什么才是面向对象编程(OOP),下面就简单从多个方面进行分析,当然下面只是我个人的一些见解。
    在分析这个问题之前我们先来分析一下当前比较流行的编程思想,目前个人从概念上接解比较多的有三种:面向对象,面向过程的编程方法,首先举例来说一下这两种思想之前的区别。这里我举一个编译原理课程上我曾做过的一个project:设计一个具有+-*/的简单计算器,下面来看一下这两种编程思想之间的区别。
    1> 面向过程:这是一个最为简单的编程方法,或许也是我们看到这个问题时第一反应的解决方法,四种操作嘛,if else判断一下不就搞定了,如果嫌if else不好用,还有switch case嘛(其实没区别呀^^),或许我们写出的代码应该是这样的
    float calc(char symbol, float a, float b) 
         switch(symbol) 
         case '+':    return a + b; 
         case '/':    return a / b; 
     } }
哈哈,很简单吧,一个switch搞定了这个简单的计算器
对于 (a + b - c * d)/e,这个表达式怎么计算呢,我想还是很容易使用calc这个函数进行处理的吧,自己写一下吧。

    2> 面向对象:面向对象最重要的就是对象,在学习C++时我们一直强调所有的东西都是对象,那么针对这个问题什么才是对象呢?操作符,操作数?不错,他们都是对象。回想一个类的三个重要特性:封装性,继承性,多态性。其中封装和继承很容易理解,多态的概念相对复杂一些,如果不理解请猛戳 这里。既然理解了三个概念,那么我们就开始着手解决计算器这个问题,我们将操作符抽象成对象,类或许应该这样设计:
class Operator { 
 virtual Type calc(Type a, Type b) = 0;
}
class Add : public Operator 
 virtual Type calc(Type a, Type b) {return a + b; }
}
.. ...
class Div : public Operator 
 virtual Type calc(Type a, Type b) {return a / b; }
}
定义了这些操作符之后,我们还需要一个方法来生成这些对象,这个时候我们一般会使用一个Factory(工厂模式)来生成这些操作符对象,那么计算器是如何利用这些对象呢? 对于(a + b - c * d) / e,解释器(interpretor)使用Factory将这句话转换成:
   op4.calc(op3.calc((op1.calc(a, b), op2.calc(c, d)), e)
其中opN是操作符的对象(类型都是Operator),由Factory生成,计算器不关心每个操作符里面进行了哪些操作。

分析:
    这个时候我们或许已经看到了面向过程和面向对象之间的一些区别,到目前为止你或许会说,面向对象就是在扯淡,将一个本来几行代码就完成的事情搞行这么复杂,代码还多写了那么多,并且面向对象的代码读起来还比较晦涩,何必呢!
    是的,当一个问题非常非常简单的时候,使用简单的if else确认会省很多事情,并且很直白,但是当问题开始变得复杂起来,我需要增加更多的运算符,怎么办呢? 第一种写法就是在switch中添加更多的分支,当然可以,但是当问题本身开始变得复杂,例如增加对复数运算的支持,那么我想这时的calc函数会变得异常庞大,以至于将来的维护非常困难,或许将case下的操作都搬运到不同的函数中去处理可以解决一些问题,不过一旦问题复杂到这种需要拆分函数的时候,我想一个后来的维护者可能更愿意在已有的代码上去添加自认为简单的case分支或者修改已有的逻辑,而不是首先想着去对代码重构(我们这种心态大家都曾有过,试问谁不想规避一下风险呢^^),以致于后来代码越来越臃肿。
    而在面向对象的处理方法中,每添加一个新的操作,你要做的是添加一个新的类型(class)和在Factory中添加一行代码,这种修改不会对已有的逻辑产生影响,即使修改已有的一个操作,也不会对其它操作产生影响。

问题:
    好吧,现在回到之前提出的问题,什么是面向对象?我想既然是面向对象,第一步首先是对象,不管是现实中的对象,还是逻辑中的对象,每一个对象都不是孤立存在的,对象之前是有一定联系的,大家都会有一定的共性,是鸟都会飞(别去管鸵鸟),那么飞就是一个共性,天鹅会捕鱼,猫头鹰很捉老鼠...,这是他们的特性,如此就体现出继承和派生的重要性,派生出特性,继承自共性。
    即使大家都会飞,飞的姿式双完全不同,大自然拥有无数的鸟类的对象,大自然对每个对象下飞的命令,每个对象都表现出自己的飞行姿式,这就是多态,只有有了多态的时候,大自然才会如此的丰富,并且表现的如此的简单,协调而统一。
    毋庸置疑,每个对象都有属性和行为,这些属性和行为应当是由对象来持有,这就封装,因为每个对象都封装了自己的行为和属性,才使得整个系统变得更加简单,否则在一个复杂的系统中会因管理如此多的属性和行为而变得不堪重负。

   上面总结了class的三个特性,封装,继承和多态,那么无容置疑,面向对象编程这三个特性是必须的,其中三个特性缺乏一个我想都不会是严格意义上的面向对象编程,然后在实际使用中我们更多的利用了封闭和继承这两种特性,最容易忽略的是多态的使用,在C++的这种静态的语言中更能体现出多态的重要性,然而现在我们更多的是使用动态的编程语言,python,lua等等,多态的概念或许并不那么重要,虽然在这些语言中我们不会提及多态,但我觉得动态语言本身就是多态的,也可以说是多态无处不在,正因如此我们才应更好的去利用封装和继承来处理问题。
    另外,我觉得即使在代码中使用了类的三个特性,写出来的代码也不一定是面向对象的编程方法,面向对象的编程我更觉得是使用一种(面向)对象的思维去处理问题,例如当你看到一个人的时候,这个人是由什么组成的,手,头,脚等等,这些是什么呢?是的,他们是不同的对象,人让手去握拳,人(大脑)是发出一个指令,具体这个动作是由手这个对手完成的,具体怎么完成的,人(大脑)不需要也不应该care(否则这个人就太累了)。
    那么面向对象解决了什么问题呢?封装变化,我想应该是解决这个问题,软件工程中一个最大的问题是变化,所以系统设计之初就应当考虑到未来的变化,可能会有人说我眼下的问题只是解决+-*/这几个简单的操作,这时我还是花很多时间去设计抽象类对象,这是一种过度设计,这种说法或许是有道理的。但是如果这几个操作是一个大型系统中的一个子系统,又或许每一个子系统都简单的像+-*/,如果只是因为他们太过简单而不去设计,我想随着系统的不断膨胀,最后会变得难以维护。
    面向对象编程与面向对象语言之前有什么关系,二者之间没有必然的关系,C++,Java是面向对象编程语言,C是非面向对象的编程语言,但C同样可以进行面向对象编程,最好的例子就是Linux内核(我没去读过linux的内核代码,但是大家都如是说),但用C进行面向对象编程或许不同一般人都做得到的,至少你需要去使用各种宏定义去实现继承和多态,而C++,Java等可以很方便的实现面向对象编程,当然你也非常容易使用面向对象语言实现面向过程。

    最后,不管是用面向对象还是用面向过程,我们都要去创造一个高内聚,低耦合的系统,这才是我们系统设计的目标。
    










  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值