已锁定 主题:Why OO sucks
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间: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 好用。 |
|
返回顶楼 | |
发表时间: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 |
|
返回顶楼 | |
发表时间: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实现的,函数参数类型是一样的。 |
|
返回顶楼 | |
发表时间: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() 呢。 |
|
返回顶楼 | |
发表时间: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干嘛呢? |
|
返回顶楼 | |
发表时间: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 语言决斗吧。 |
|
返回顶楼 | |
发表时间: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)来实现的。 比如,两个类型只有一个方法不同,其他方法都是相同的。 |
|
返回顶楼 | |
发表时间: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) } |
|
返回顶楼 | |
发表时间: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定义类型那么直观和便利。 |
|
返回顶楼 | |
发表时间: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 贯彻始终,把类视为顶级公民,在处理过程中把闭包搞成了匿名类,但这并不妨碍我们对它的识别。 |
|
返回顶楼 | |