论坛首页 综合技术论坛

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

浏览 48555 次
该帖已经被评为良好帖
作者 正文
   发表时间:2010-07-14   最后修改:2010-07-23
加个通道:G A E - R P R O X Y, http://www.iteye.com/topic/717232

没想到写了这么多。本文并不是要否定OO,而是要给PO更多的肯定。这篇文字不像想象中那么长,只是些一看便知的代码占了些篇幅,请大家花3分钟看完,这将会是个很有意义的讨论。为了方便大家阅读,我把提纲先列在上面。
1。 我们需要全局变量和函数。
2。 我们需要Callback函数。
3。面向对象的代码在重构和重用上没有面向过程的灵活
引申:数据与逻辑的绑定还是分离?
引申:面向对象曾经辉煌但已褪色的光辉
引申:面向对象最有魅力的地方在哪?
尾声:什么时候用OO,什么时候用PO?

回复ray_linn的C#代码:
http://www.iteye.com/topic/712942?page=2#1580812
---------------------
面向对象在过去的十多年里一直被广泛的宣传,现在已经成为世所公认的比面向过程更优秀的编程模式,但是——过犹不及。

[del]Java将被作为面向对象编程语言的典型来做说明,Python将被作为面向过程的语言来说明,虽然Python也面向对象。[/del]
有人说我是在说Java语言的问题,而不是说OO的问题,所以我把OO的代码也改成了python实现。


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

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

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

2。 我们需要Callback函数。

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

def some_function(param...)
   //my codes...

addListener('some_event',some_function)

而试图完全对象化的Java语言有一个很尴尬的做法
class MyCallbackImpl:
   def myCallbackMethod(MyParam param,...):
     //My codes...

someObj.addListener('some_event',MyCallbackImpl());

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

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

比如这样的一段代码:
class MyClassA:
  def methodA(self,ParamA){
    //根据ParamA,this.someField得出返回值

class MyClassB:
  def methodB(self,ParamB):
     //根据ParamA,this.someField得出返回值
...
objA = MyClassA();
objA.methodA(paramA)
objB = MyClassB();
objB.methodB(paramB)


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

这里的面向过程的代码中出现了MyClassA和MyClassB,但这两个类完全是空的,你可以只理解为是一个数据结构而已。

现在需求发生了改变,MyClassA需要实现类似methodB的功能,MyClassB要实现类似methodA的功能。
我们先看看,面向过程的代码要做什么修改:
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)

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

==================================================================

引申:数据与逻辑的绑定还是分离?
面向对象编程在代码逻辑上是意味着什么?个人认为面向对象在代码逻辑上意味着数据与逻辑的绑定。可以想象成 C的Structure和C的function结合成了Cpp的Class。
面向过程在代码逻辑上意味着什么?个人认为面向过程在代码逻辑上意味着数据与逻辑的分离。
我们经常说MVC,数据、逻辑、视图分离。那么我们在最基本的代码上就不需要这种分离了吗?
程序=数据结构+算法 ,对象也可以理解为数据结构和算法的绑定, 对象更加的接近一个程序的完整结构,而过程则更像一个代码段。
从这个角度看,很难说这是优点或缺点。

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

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

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

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

个人认为,面向对象最大的吸引力在于他的表现力。看这样一段代码:
class Fish{
  def swim(){
   //the fish swimming

fish=Fish()
fish.swim()

来看面向过程的实现
def swim(fish):
  //the fish swimming

fish = Fish()
swim(fish)

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

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

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

Use OO as data-structure more than design patterns, more static utility functions.
   发表时间:2010-07-14  
说的还是状态保存在哪里的问题,OO将状态保存在对象里,PO将状态保存在方法参数之中,PO的方法更容易做到没有副作用,组合起来当然更容易。而OO要处理状态,状态的组合却不是那么容易,要处理覆盖、同名、别名等情况,并且OO将类型信息也附加于对象之上,处理起来更是麻烦了。
2 请登录后投票
   发表时间:2010-07-15   最后修改:2010-07-15
引用
浮在海上的冰山,大部分的内容在海面以下。海面以上的用OO来表现会更美,海面以下的用PO来表现会更合适。
对最后的这个结论有点感觉,不过没仔细研究过。但是我觉得lz举的例子不足以推出这个结论。

1、首先Java似乎算不上典型的面向对象语言。然后说这个static,Ruby中对应Java的静态方法有类方法,但Ruby的类是个对象,所以类方法也是对象的方法。只是这个对象比较特别,生命周期比较长,作用域相对广些吧……看起来只是个概念定义的问题。对于“我们需要全局性的变量、全局性的函数”,我也觉得是这样

2、Java中事件监听似乎多用匿名类,相对麻烦些,这个似乎只是因为Java中的方法不是一个对象,不能直接当参数传递给某个方法。JavaScript中的function、Ruby里的proc都是一个对象。从你的代码结合我对python粗浅了解过的一丁点印象中,好像python的function也是个对象。

3、不懂python……仔细看看像是给同一个函数传递不同类型的参数,这是强类型和弱类型的问题,也应该算不上OO和PO的问题吧。

引用
我们经常说MVC,数据、逻辑、视图分离。

MVC是视图、逻辑分离,中间搭个控制器。数据和业务逻辑再分离出去是大部分SSHer的做法,就是传说中的贫血模型吧。陶文同学介绍了个qi4j似乎是一剂良药,但那之后俺钻到Ruby中去就没了解了。

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

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

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

这后半段内容在以前我会不以为然,不过学了一段时间JavaScript之后挺同意的。
关于前半段,那个包的概念跟Java的package是不是同一回事?如果是的话,那好像也只能说PO比OO少了些东西……作用域的控制上还是OO可控性好些吧。
1 请登录后投票
   发表时间:2010-07-15  
dennis_zane 写道
说的还是状态保存在哪里的问题,OO将状态保存在对象里,PO将状态保存在方法参数之中,PO的方法更容易做到没有副作用,组合起来当然更容易。而OO要处理状态,状态的组合却不是那么容易,要处理覆盖、同名、别名等情况,并且OO将类型信息也附加于对象之上,处理起来更是麻烦了。

嗯,是的,这是导致“面向对象的代码在重构和重用上没有面向过程的灵活”的主要原因。
0 请登录后投票
   发表时间:2010-07-15   最后修改:2010-07-15
恩,Java不是OO语言的全部吧。回调函数在C#里就很处理并不尴尬,(当然用C++搞就更不尴尬了),从楼主的例子上看,只能说Java太固步自封了,在C#出来之前一直没有进步。

class A
{
      public event ProcessDelegate ProcessEvent;
}      

var a =new A(); 
a.ProcessEvent += new ProcessDelegate(t_ProcessEvent);


也可以这样搞
        class A<T>
        {
            public void MethodA(Func<T> fun)
            {
                fun.Invoke();
            }
        }


第二个问题就更简单了,C#中有扩展方法,我们给A,B做个伪接口
interface Fake{}
Class A :Fake{}
Class B :Fake{}
static Class Ext
{
   TypeA MehtodA(this Fake ojb, ParamA){}
   TypeB MethodB(this Fake obj, ParamB){}
}

调用时
A.MethodA(...) A.MethodB(...), B.MethodA(...),B.MethodB(...); 如果问题再具体点,还有更多有趣的方法。


0 请登录后投票
   发表时间:2010-07-15  
yuan 写道

1、首先Java似乎算不上典型的面向对象语言。然后说这个static,Ruby中对应Java的静态方法有类方法,但Ruby的类是个对象,所以类方法也是对象的方法。只是这个对象比较特别,生命周期比较长,作用域相对广些吧……看起来只是个概念定义的问题。对于“我们需要全局性的变量、全局性的函数”,我也觉得是这样

2、Java中事件监听似乎多用匿名类,相对麻烦些,这个似乎只是因为Java中的方法不是一个对象,不能直接当参数传递给某个方法。JavaScript中的function、Ruby里的proc都是一个对象。从你的代码结合我对python粗浅了解过的一丁点印象中,好像python的function也是个对象。


其实想表达的是,全局函数、函数指针、函数引用本质上都是PO的概念。
为了OO而OO的设计出callable对象,个人觉得是一件画蛇添足的事情。

yuan 写道

3、不懂python……仔细看看像是给同一个函数传递不同类型的参数,这是强类型和弱类型的问题,也应该算不上OO和PO的问题吧。

贴的代码造成了这个误解,想表达的是2L dennis_zane的观点。

yuan 写道

这后半段内容在以前我会不以为然,不过学了一段时间JavaScript之后挺同意的。
关于前半段,那个包的概念跟Java的package是不是同一回事?如果是的话,那好像也只能说PO比OO少了些东西……作用域的控制上还是OO可控性好些吧。

是的,PO比OO少了些东西,但PO不再像以前那样一无所有了。
0 请登录后投票
   发表时间:2010-07-15  
如果需要一个有属性状态的东西 就用对象 如果有些方法都是作用在这个或者这些属性上 就是用绑定方法 至少getter setter这些方法还是与数据绑定的

如果方法只用来处理数据 而不关心这些数据来自于哪个对象 那就是过程 一些static的东西完全可以剥离出来 只是和当前所在类定义的东西有且仅有相关的操作 就没必要剥离出来

在我看来所谓的对象就分2-3种来定义就好
1、逻辑对象 处理业务逻辑 本身是有数据状态的
2、应用类 就是static方法的集合类 没有什么属性状态 或者都是些不变的属性 或者是可变但是公用的 这个根本算不得对象
3、这个可以有 也可以无 我通常会放 就是用来和数据库做ORMapping的 通常只有setter getter方法 1的对象要对此作业务上的处理 然后由ORMapping的操作程序负责和数据库进行数据的交换
0 请登录后投票
   发表时间:2010-07-15  
可惜不能投新手帖。

随便找几个毫无意义的例子就出来否定OO,可笑可笑。
扩展性和适应变化正是OO最大优点,竟然说不如PO,简直一派胡言。
劝君学习一下设计模式再出来发表高论,免得误人子弟,怡笑大方。
2 请登录后投票
   发表时间:2010-07-15  
喂, 过程和函数是2个东西
0 请登录后投票
   发表时间:2010-07-15  
yangguo 写道
可惜不能投新手帖。

随便找几个毫无意义的例子就出来否定OO,可笑可笑。
扩展性和适应变化正是OO最大优点,竟然说不如PO,简直一派胡言。
劝君学习一下设计模式再出来发表高论,免得误人子弟,怡笑大方。


这绝对不能算新手贴。反而我觉得你比较新手更多一点。
1 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics