面向对象之弊 面向过程之优

开发
面向对象在过去的十多年里一直被广泛的宣传,现在已经成为世所公认的比面向过程更优秀的编程模式,但是——过犹不及。本文并不是要否定OO,而是要给PO更多的肯定。这篇文字不像想象中那么长,只是些一看便知的代码占了些篇幅,请大家花3分钟看完,这将会是个很有意义的讨论。

面向对象在过去的十多年里一直被广泛的宣传,现在已经成为世所公认的比面向过程更优秀的编程模式,但是——过犹不及。Java将被作为面向对象编程语言的典型来做说明,Python将被作为面向过程的语言来说明,虽然Python也面向对象

1、我们需要全局变量和函数

java作为一个典型的面向对象的编程语言,为什么要设static关键字。这从侧面说明,面向对象不是***的。我们需要全局性的变量、全局性的函数(方法)。

单例的设计模式,是试图用面向对象的方法来做全局性的函数。因为对象只会被创建一次,那该对象的方法事实上就是一个全局函数。即便单例可以用面向对象的方法来解决了全局函数的问题,但要获取单例的实例,我们依然无法避免使用static变量来hold这个实例,无法避免使用static函数来获取这个实例。

2、我们需要Callback函数

面向过程的语言会有类似这样的代码:

  1. Python代码   
  2. def some_function(param...)     
  3.    //my codes...     
  4.     
  5. addListener('some_event',some_function)    
  6. def some_function(param...)  
  7.    //my codes...  
  8. addListener('some_event',some_function) 

而试图完全对象化的Java语言有一个很尴尬的做法,Java代码:

  1. interface MyCallback{     
  2.    MyReturenType myCallbackMethod(MyParam param,...);     
  3. }     
  4. class MyCallbackImpl implement MyCallback{     
  5.    MyReturenType myCallbackMethod(MyParam param,...){     
  6.      //My codes...     
  7.    }     
  8. }     
  9. someObj.addListener(new MyCallbackImpl());    
  10.  
  11. interface MyCallback{  
  12.    MyReturenType myCallbackMethod(MyParam param,...);  
  13. }  
  14. class MyCallbackImpl implement MyCallback{  
  15.    MyReturenType myCallbackMethod(MyParam param,...){  
  16.      //My codes...  
  17.    }  
  18. }  
  19. someObj.addListener(new MyCallbackImpl()); 

我们可以看出,为了这个回调,我们定义了接口,定义了实现类,并且构造了 MyCallbackImpl的对象,并且降低了代码的可读性。我见过许多对回调很晕的同学,我想不是他们的理解能力问题,而是面向对象的这种做法本身的问题。

#p#

3、面向对象的代码在重构和重用上没有面向过程的灵活

比如这样的一段代码,Java代码:

  1. class MyClassA{     
  2.   TypeA methodA(ParamA){     
  3.     //根据ParamA,this.someField得出返回值     
  4.   }     
  5. }     
  6.     
  7. class MyClassB{     
  8.   TypeB methodB(ParamB){     
  9.      //根据ParamA,this.someField得出返回值     
  10.   }     
  11. }     
  12. ...     
  13. MyClassA objA = new MyClassA();     
  14. objA.methodA(paramA)     
  15. MyClassB objB = new MyClassB();     
  16. objB.methodB(paramB)    
  17.  
  18. class MyClassA{  
  19.   TypeA methodA(ParamA){  
  20.     //根据ParamA,this.someField得出返回值  
  21.   }  
  22. }  
  23.  
  24. class MyClassB{  
  25.   TypeB methodB(ParamB){  
  26.      //根据ParamA,this.someField得出返回值  
  27.   }  
  28. }  
  29. ...  
  30. MyClassA objA = new MyClassA();  
  31. objA.methodA(paramA)  
  32. MyClassB objB = new MyClassB();  
  33. objB.methodB(paramB) 

methodA只与paramAmethodA被限定在MyClassA的对象中调用,methodB被限定在MyClassB的对象中调用,这两个方法由于业务范畴的原因被归入相应的Class。让我们来看看这样的代码用面向过程的方式会如何写,Python代码:

  1. def methodA(paramA,paramField):     
  2.    //根据ParamA,paramField得出返回值     
  3. def methodB(paramB,paramField):     
  4.    //根据ParamB,paramField得出返回值     
  5.     
  6. class MyClassA{     
  7. }     
  8. class MyClassB{     
  9. }     
  10. ...   
  11.  
  12. objA = MyClassA()     
  13. objB = MyClassB()     
  14. methodA(paramA,objA.someField)     
  15. methodB(paramB,objB.someField)    
  16.  
  17. def methodA(paramA,paramField):  
  18.    //根据ParamA,paramField得出返回值  
  19. def methodB(paramB,paramField):  
  20.    //根据ParamB,paramField得出返回值  
  21.  
  22. class MyClassA{  
  23. }  
  24. class MyClassB{  
  25. }  
  26. ...  
  27. objA = MyClassA()  
  28. objB = MyClassB()  
  29. methodA(paramA,objA.someField)  
  30. methodB(paramB,objB.someField) 

这里的面向过程的代码中出现了MyClassA和MyClassB,但这两个类完全是空的,你可以只理解为是一个数据结构而已。现在需求发生了改变,MyClassA需要实现类似methodB的功能,MyClassB要实现类似methodA的功能。我们先看看,面向过程的代码要做什么修改,Python代码:

  1. def methodA(paramA,paramField):     
  2.    //根据ParamA,paramField得出返回值     
  3. def methodB(paramB,paramField):     
  4.    //根据ParamB,paramField得出返回值     
  5.     
  6. class MyClassA{     
  7. }     
  8. class MyClassB{     
  9. }     
  10. ...     
  11. objA = MyClassA()     
  12. objB = MyClassB()     
  13. methodA(paramA,objA.someField)     
  14. methodB(paramB,objB.someField)     
  15. #增加下面的两句     
  16. methodB(paramA,objA.someField)     
  17. methodA(paramB,objB.someField)    
  18.  
  19. def methodA(paramA,paramField):  
  20.    //根据ParamA,paramField得出返回值  
  21. def methodB(paramB,paramField):  
  22.    //根据ParamB,paramField得出返回值  
  23. class MyClassA{  
  24. }  
  25. class MyClassB{  
  26. }  
  27. ...  
  28. objA = MyClassA()  
  29. objB = MyClassB()  
  30. methodA(paramA,objA.someField)  
  31. methodB(paramB,objB.someField)  
  32. #增加下面的两句  
  33. methodB(paramA,objA.someField)  
  34. methodA(paramB,objB.someField) 

可是面向对象的代码呢?等待他的将是代码的重构,也许他可以选择的重构方式是static函数————本质上是一种面向过程的方式。

#p#

引申:数据与逻辑的绑定还是分离?

面向对象编程在代码逻辑上是意味着什么?个人认为面向对象在代码逻辑上意味着数据与逻辑的绑定。可以想象成 C的Structure和C的function结合成了Cpp的Class。
面向过程在代码逻辑上意味着什么?个人认为面向过程在代码逻辑上意味着数据与逻辑的分离。

我们经常说MVC,数据、逻辑、视图分离。那么我们在最基本的代码上就不需要这种分离了吗?程序=数据结构+算法,对象也可以理解为数据结构和算法的绑定, 对象更加的接近一个程序的完整结构,而过程则更像一个代码段。从这个角度看,很难说这是优点或缺点。

引申:面向对象曾经辉煌但已褪色的光辉

面向对象出现之初,还是c语言时代,充满了无层次结构的函数,面向对象给函数带来了归属地,让函数可以被更好的整理。而如今,面向过程的语言,也可以通过包的概念来整理函数的归属。

此外,OO带来访问控制的一些概念,private,protected,public,这些访问控制的确令人眼前一亮,但很难说他还有吸引力。对于访问控制,在编译原理上面向过程的语言同样可以实现,但更重要的还是一个好的编码习惯,比如python的__前缀函数,开发者会自然的规避调用它。

引申:面向对象最有魅力的地方在哪?

个人认为,面向对象***的吸引力在于他的表现力。看这样一段代码,Java代码:

  1. class Fish{     
  2.   void swim(){     
  3.    //the fish swimming     
  4.  }     
  5. }     
  6.     
  7. Fish fish=new Fish()     
  8. fish.swim()    
  9. class Fish{  
  10.   void swim(){  
  11.    //the fish swimming  
  12.  }  
  13. }  
  14. Fish fish=new Fish()  
  15. fish.swim() 

来看面向过程的实现,Python代码:

  1. def swim(fish):     
  2.   //the fish swimming     
  3. fish = Fish()     
  4. swim(fish)    
  5. def swim(fish):  
  6.   //the fish swimming  
  7. fish = Fish()  
  8. swim(fish) 

面向对象的代码,我们很直观的看到 fish.swim() 是鱼游泳。而面向过程的代码则是 swim(fish),游泳这条鱼,函数定义也许改做 make_fish_swim(fish) 更合适。

尾声:什么时候用OO,什么时候用PO?

浮在海上的冰山,大部分的内容在海面以下。海面以上的用OO来表现会更美,海面以下的用PO来表现会更合适。

【编辑推荐】

  1. Python继承体现面向对象特征
  2. PHP+Java的开发经验:不要太面向对象
  3. 面向对象设计原则之单一职责 

 

责任编辑:王晓东 来源: javaeye
相关推荐

2022-07-30 23:41:53

面向过程面向对象面向协议编程

2023-11-30 08:00:54

面向对象面向切面

2023-04-26 00:15:32

python面向对象java

2023-01-10 09:38:09

面向对象系统

2019-06-13 11:50:41

Python面向对象编程语言

2013-03-11 09:23:22

Go语言面向对象

2023-03-10 07:43:50

UML图OOA面向对象

2011-07-05 14:42:46

java

2010-07-08 13:35:39

UML面向对象

2010-12-23 13:35:05

面向过程

2009-10-21 18:09:12

VB入门教程

2009-09-27 14:12:12

面向对象设计单一职责

2017-04-21 09:07:39

JavaScript对象编程

2012-01-17 09:34:52

JavaScript

2013-08-21 17:20:49

.NET面向对象

2013-04-17 10:46:54

面向对象

2015-10-16 13:41:52

程序对象设计

2013-03-14 11:17:46

2017-06-23 14:40:29

存储数据库逻辑分离

2012-06-07 10:11:01

面向对象设计原则Java
点赞
收藏

51CTO技术栈公众号