白马非马

  战国的时候有一位公孙龙先生,提出了这么一个观点,说“白马非马”。我们的教科书上说那叫诡辩,白马明明也是马么。那么咱先写个程序来验证一下:

python程序:
class Horse:
    pass

class WhiteHorse(Horse):
    pass

print WhiteHorse == Horse

结果是:
False

再用ruby写一个:
class Horse
end

class WhiteHorse < Horse
end

puts Horse == WhiteHorse

结果是:
false

  你看,白马还真就不是马。

  回头来看看公孙龙先生是怎么解释的:“马者,所以命形也;白者,所以命色也。命色者非命形也,故曰:白马非马。”“求‘马’,‘黄’‘黑’马皆可致,求‘白马’,‘黄’‘黑’马不可致。”“马固有色,故有白马。使马无色,有马如己耳。安取白马?故白者,非马也。白马,马与白也,白与马也。故曰:白马非马也。”马和白马不是同一个概念,所以白马不是马。我们的教科书说这是否认种概念包含于其类概念外延之中的逻辑错误,也就是说,马包含白马,抽象概念包括具体概念。所以说,白马是马。这似乎是不错的。那前面的程序的结果又明明白白的说,白马不是马,也就是说,抽象概念和具体概念是不相等的。这应该也是对的。那问题处在了哪里呢?实际上,白马是不是马取决于对“是”的理解。在E文里,有两种不同的写法:is a和is the。a white horse is a horse是对的,the “white horse” is the “horse”是错的。结合前面的程序,这就很明显了。说白马是马的意思是,白马是马的子类。说“白马不是“马的意思是,“白马”和“马”是不同的实体。而我们之所以会对“白马非马”产生争论就是因为这个“非”或者“是”有不同的意义。

  不是所有的语言都能写出上面的程序的。在python和ruby中,类本身也是对象,所以才可以进行比较。在面向对象语言中,类和对象都是基本的概念。类是对象的描述,对象是类的实例。比如,可以定义一个马的类,其中有一个属性是颜色,然后建立一个马的对象,把它的颜色属性设为白色,这就是白马了。但是,白马也有许多,刘备的的卢和唐僧的白龙马是不一样的。所以,可以建立一个白马的类,让它继承马这个基类。它的所有实例对象的颜色属性都是白色。

  什么时候需要建立像白马那样的类呢?有种说法是,任何抽象的描述都是类,具体的东西是对象。那抽象和具体的界限是什么呢?比如在M$的VS的GUI程序里,通常每一个窗体都有一个自己的类,虽然通常他们都只有一个实例,但也有有许多实例的窗体,比如MDI界面种的子窗体。在网上书店里,同一版的书被认为是同一本书例如,每一本1991年版第一次印刷的《三国演义》都是一样的。但在图书馆管理系统中就需要区分每一本书。但不管在网上书店还是图书馆管理系统,都不会去建立“1991年版第一次印刷的《三国演义》”这样的类,虽然这仍然可以说是一个抽象的概念。事实上,如果真的为每一个抽象概念都建立一个类的话,类的数量就会达到无法维护的地步。而我们往往也并不需要在实际应用中建立如此细致的抽象概念,比如在网上书店中,抽象概念只需要具体到“这是一本书”就可以了。其实在日常也是如此。

  现代的面向对象理论认为,面向对象编程不是面向类编程,而应该是面向接口编程。一个对象是什么取决于它实现的接口,也就是它能做什么。如果在某个环境中,一个能象鸭子那样摇摇摆摆得走,并且嘎嘎叫的就是一只鸭子,那么哪怕它只是个上发条的玩具,在这个只关心这两电环境中,它也就是一个真的鸭子。这就是所谓的duck typing。这里的“接口”并不等同于java等语言中的interface,interface更像是一个缩水的类。比如,只要有一个bark方法的对象就是能叫唤的东西,这个back方法本身就是一个接口。而类只是类型的一种实现方式,可以说是对象的一个模板,用来方便得建立一些具有共性的对象。

  回到开头的程序。我们是不是需要建立像“白马”这样的类呢?这是要看具体情况的。比如开始我们只有几匹马,客户也不挑剔马的颜色,那么就没有这个必要。但是如果有了很多喜欢白马的公主或是喜欢黑马的,为了能更方便的满足他们的需求,就有可能需要建立“白马”类来更方便得创建白马。但是在许多编程语言中,“类”都是比较硬的。改变一个对象的类经常会牵一发而动全身,需要修改许多地方的代码。所以就有了设计模式,让这些改动变得容易一点。而在动态语言中,并不在编译期检查对象的类型,只要对象有这个方法或属性,就可以访问。从这方面说,动态语言更接近于真正的面向对象编程,而不是面向类编程。

5 thoughts on “白马非马

  1. DigitalSonic

    感觉你的程序照你这种写法永远都是false,怎么会对两个类用==呢,好歹换成两个实例吧,我的结论就是白马是马,有运行结果为证,呵呵.
    class Horse
    end
    class WhiteHorse < Horse end wh = WhiteHorse.new puts wh.is_a? Horse 结果为true

    Reply
  2. pp

    编程在下不行。但白马非马你要说啥还是懂了。
    其实白马是马中的判断动词“是”的意思因该是“集合‘白马’中的元素包含于集合‘马’。”

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.