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

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

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

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

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

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

2、我们需要Callback函数

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

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

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

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

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

#p#

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

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

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

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

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

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

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

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

#p#

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

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

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

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

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

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

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

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

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

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

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

面向对象的代码,我们很直观的看到 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语言面向对象

2011-07-05 14:42:46

java

2023-03-10 07:43:50

UML图OOA面向对象

2010-07-08 13:35:39

UML面向对象

2010-12-23 13:35:05

面向过程

2009-10-21 18:09:12

VB入门教程

2013-04-17 10:46:54

面向对象

2013-08-21 17:20:49

.NET面向对象

2009-09-27 14:12:12

面向对象设计单一职责

2017-04-21 09:07:39

JavaScript对象编程

2012-01-17 09:34:52

JavaScript

2015-10-16 13:41:52

程序对象设计

2013-03-14 11:17:46

2012-12-13 11:01:42

IBMdW

2021-10-21 18:47:37

JavaScript面向对象
点赞
收藏

51CTO技术栈公众号