论坛首页 综合技术论坛

Why OO sucks

浏览 50424 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-08-21  
buaawhl 写道


个人感觉。从来没有觉得对象能够表达现实世界的任何东西。对象只能表达编程元素。
能够打包,确实是OO的好处。尤其是带有多态的打包。
打包很简单。C语言、FP语言都可以打包(放到Tuple、Array里面)。

打包是为了啥呢?为啥OO的打包就那么特殊呢?OO打包的特点在于多态。
多态是为了啥呢?是为了 callback 模式形式的重用。也叫做Template模式。
在callback (or template) 重用模式下,OO是无敌王者。

template( callback) { // 这里重用的是template
.....

callback.run(....)
.....
}

可惜,只依靠这一点,并不足以击败FP。FP的函数直接就可以作为参数和返回值,在callback重用模式更有优势。
OO只能依靠来自于C语言的状态(可重复赋值)特性来击败FP。
OO的打包可以很自然地携带数据(有状态),同时具有多态。

FP的打包,可以分为两种。
(1) Funciton本身。这种情况下,callback重用有优势。甚至优于OO对象。但是,携带数据不方便,只能依靠闭包。而闭包是很麻烦,很不直观的。

(2) Tuple, Array里面放数据和函数。这种情况下,callback重用就比较麻烦,必须自己在template函数外部手工替换Tuple中的某一个Function。而不能达到OO多态那样的自然简单效果。





我在第一页提到了 callback 问题,第二页解释了 class 作为打包的模板的意义,我认为这两个例子足以证明 fp 和 oo 在本质上是相通的。

我想其实 oo 的提出主要是基于一种亚里士多德风格的认识论,人类看事物总是采用分类的方法,而这种方法根据历史经验,也是合理的。所以如果我们站在软件工程的角度来理解 oo,就很好理解了。比如我这个socket 收到了包,包长多少多少,完整不完整。用oo来表达很清晰,socket.onReceivePacket packet.length packet.isComplete,组织的很好,很适合在图纸上设计。如果用闭包、turple 等等来表述这些事物,往往成了 len(packet), is_complete(packet),一下子整个世界都没有主动事物了。

从错误控制和知识组织来说,packet.xxx 中,有多少种 xxx,是易于学习和便于控制的,而能有多少个操作 packet 的函数,是完全无法控制的,不知道在哪个模块又会冒出一个操作 packet 的函数来。

比如现在 erlang 用的 module 风格,操作 binary 的有哪些函数,我想谁都搞不清楚。

lisp 语言很不错,但我看 lisp 语言在软件工程中,绝对不如 oo 化了的 js 好用。
0 请登录后投票
   发表时间:2008-08-21  
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight


你要做出OO的.操作符也很简单
做一个中缀函数就完了

引用
~(P,F)=F(p)

P~F


0 请登录后投票
   发表时间:2008-08-21  
Trustno1 写道
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight



从OO的角度来看,上述这些是 Overload (函数参数类型不同)。

OO的多态是override实现的,函数参数类型是一样的。

0 请登录后投票
   发表时间:2008-08-21  
Trustno1 写道
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight


你要做出OO的.操作符也很简单
做一个中缀函数就完了

引用
~(P,F)=F(p)

P~F()




是挺不错,那我要做一个 class, 以便以后 new Person() 呢。
0 请登录后投票
   发表时间:2008-08-21  
buaawhl 写道
Trustno1 写道
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight



从OO的角度来看,上述这些是 Overload (函数参数类型不同)。

OO的多态是override实现的,函数参数类型是一样的。


有了polymorphism,要override干嘛呢?

0 请登录后投票
   发表时间:2008-08-21  
Trustno1 写道
buaawhl 写道
Trustno1 写道
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight



从OO的角度来看,上述这些是 Overload (函数参数类型不同)。

OO的多态是override实现的,函数参数类型是一样的。


有了polymorphism,要override干嘛呢?



那就是同一回事了,这其实也是 ooa, 大家都是一家人。去找 c 语言决斗吧。
0 请登录后投票
   发表时间:2008-08-21  
Trustno1 写道
buaawhl 写道
Trustno1 写道
引用
OO的打包可以很自然地携带数据(有状态),同时具有多态

只要有类型就能做polymorphism,和是否OO,fp没有关系.
比如这样
class Entity a where
getPosition :: a -> (Int,Int)
getVelocity :: a -> (Int,Int)
getAcceleration :: a -> (Int,Int)
getColor :: a -> Color
getShape :: a -> Shape



data Paddle =
Paddle { paddlePosX, paddlePosY,
paddleVelX, paddleVelY,
paddleAccX, paddleAccY :: Int,
paddleColor :: Color,
paddleHeight :: Int,
playerNumber :: Int }


引用
instance Entity Paddle where
getPosition p = (paddlePosX p, paddlePosY p)
getVelocity p = (paddleVelX p, paddleVelY p)
getAcceleration p = (paddleAccX p, paddleAccY p)
getColor = paddleColor
getShape = Rectangle 5 . paddleHeight



从OO的角度来看,上述这些是 Overload (函数参数类型不同)。

OO的多态是override实现的,函数参数类型是一样的。


有了polymorphism,要override干嘛呢?



这是Haskekell的类型定义吧。
能不能给一个类型继承的例子。OO多态就是依靠inherit(对于interface叫做implement)来实现的。

比如,两个类型只有一个方法不同,其他方法都是相同的。


0 请登录后投票
   发表时间:2008-08-21  
buaawhl 写道


这是Haskekell的类型定义吧。
能不能给一个类型继承的例子。OO多态就是依靠inherit(对于interface叫做implement)来实现的。

比如,两个类型只有一个方法不同,其他方法都是相同的。




function dog(method){
    if(method == 'say'){
         return function(){
             alert('dog dog dog');
         }
    } else if(method == 'look'){
         return function(){
            alert('还行');
         }
    }
}

function habadog(method){
    if(method == 'look')  // 覆盖 look 方法
       return function(){alert('漂亮');}
    else
       return dog(method)
}

0 请登录后投票
   发表时间:2008-08-21  
inshua 写道
buaawhl 写道


这是Haskekell的类型定义吧。
能不能给一个类型继承的例子。OO多态就是依靠inherit(对于interface叫做implement)来实现的。

比如,两个类型只有一个方法不同,其他方法都是相同的。




function dog(method){
    if(method == 'say'){
         return function(){
             alert('dog dog dog');
         }
    } else if(method == 'look'){
         return function(){
            alert('还行');
         }
    }
}

function habadog(method){
    if(method == 'look')  // 覆盖 look 方法
       return function(){alert('漂亮');}
    else
       return dog(method)
}



闭包是FP语言的一种携带数据的迫不得已的方案。而且,不能“定义”类型,只能动态“产生”类型。
闭包产生类型,不如OO定义类型那么直观和便利。




0 请登录后投票
   发表时间:2008-08-21  
buaawhl 写道


闭包是FP语言的一种携带数据的迫不得已的方案。而且,不能“定义”类型,只能动态“产生”类型。
闭包产生类型,不如OO定义类型那么直观和便利。



实际上也可以定义类型。拙文 new 是什么 this 是什么有指出,见 http://blog.csdn.net/inshua/archive/2008/08/06/2776059.aspx。

这个其实不是做不做的到的问题,而是一种观念的问题。

oo 的意思就是,我必须要按这种方式思考,而 fp 语言在一开始是没有这种要求的。

就像我们写汉字一样,比如 “程”字,你可以把“程”字写的“禾”占大半部分,“呈”占小半部分,这是自由的,笔画规则也是允许的,但是最后写出来发现还是“禾”字小点比较好,写起来也快。

这个比喻里,笔画规则是 fp,而哪部分大哪部分小,这种观念性的东西是 ooa,二者并不矛盾。

至于像 java 这样的 oop 语言,它将 oo 贯彻始终,把类视为顶级公民,在处理过程中把闭包搞成了匿名类,但这并不妨碍我们对它的识别。
0 请登录后投票
论坛首页 综合技术版

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