開篇之前先說明一下,我和老莊有著不錯(cuò)的私交,他最初寫喪鐘系列的時(shí)候,我是忠實(shí)的擁躉之一,莊兄見我尚有寸尺所長(zhǎng),還在喪鐘系列里引用了我的幾個(gè)觀點(diǎn)。然而最近一段時(shí)間里,我作了這樣幾件事情:

1.重新學(xué)習(xí)了lambda演算。我的數(shù)學(xué)基礎(chǔ)不及taowen等,費(fèi)了一些時(shí)日仍不完全了然,目前大抵能對(duì)著R5RS后面的語義定義對(duì)一些簡(jiǎn)單的scheme程序進(jìn)行l(wèi)ambda演算。

2.反復(fù)研究了幾遍SICP。同時(shí)看了錄像和書(感謝曹老師下的Video),自信對(duì)前二章半有些許認(rèn)識(shí)書中未及,后二章半粗知大覽尚不能發(fā)前人所未發(fā)之言。

3.學(xué)習(xí)了Smalltalk和Ruby,Duck Typing以及其他一些有關(guān)類型系統(tǒng)的東西。

4.回顧了一下面向?qū)ο笳Z言的一些發(fā)展史,以史為鑒粗知一些興替。

5.經(jīng)日和taowen,老莊討論語言、設(shè)計(jì)等等之類,每為一辨必窮我所知爭(zhēng)發(fā)一言,所以知識(shí)可以迅速雜糅:D
經(jīng)過種種之后,發(fā)現(xiàn)當(dāng)初所謂鳴OO之喪鐘,實(shí)在是言過其實(shí)。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
第0 關(guān)于"面向?qū)ο?
既然要為人家敲喪鐘,先要找對(duì)了苦主,不然豈不是白忙活了一場(chǎng)。什么是面向?qū)ο螅窟@個(gè)問題太大,我們舉一個(gè)很常見的例子:
這個(gè)例子自然很不充分,不過繼承啊,接口啊,多態(tài)啊,略舉大概,尚可以作為一個(gè)討論的例子。從這個(gè)例子里,我們發(fā)現(xiàn)有這樣一個(gè)事實(shí),就是Person類有兩個(gè)方法

void playSolo(Instrument instrument);

void playBackground(Instrument instrument);
分別表示,需要一個(gè)類型為Instrument的對(duì)象instrument,然后對(duì)他進(jìn)行相應(yīng)的操作,而且,從概念上來講,第一個(gè)方法,使演奏旋律的,也就是單音,而第二個(gè)方法是演奏和聲的。那么,如果我有一個(gè)類
我們知道,玻璃瓶裝了水也是可以發(fā)出聲音,Mozart可是為玻璃瓶寫過曲子的,而這里我們卻不能

GlassBottle beerBottle =

.

vincent.playSolo(beerBottle);
因?yàn)槲覀冊(cè)跇?gòu)造Person類的時(shí)候,我們的play方法是依賴一個(gè)類型為Instrument的Object,換而言之,我們這里所謂的
Object-Oriented其實(shí)稱作Object-with-Type-Oriented的更合適,其實(shí)這類語言有一個(gè)專有名詞,叫做static
type object oriented。那Object-Oriented是不是就一定是Static Type Object
Oriented的呢?不然,比如在Ruby里,我們可以寫成:
然后就可以

perez711 = Guitar.new

vincent = Person.new

vincent.playSolo(perez711)
同樣也可以

vincent.playSolo(GlassBottle.new)
在這里,類型可以推演也可以留到runtime檢查,如果是推演的話,在playNote里,由于thing調(diào)用了playNote方法,所以傳進(jìn)
來的對(duì)象必須要刻意接受playNote這個(gè)消息,于是Guitar和GlassBottle都是可以通過,因此我即可以演奏我的Perez
711,也可以敲玻璃瓶。這種方式叫做dynamic type。
那么static type和dynamic type區(qū)別在那呢?static
type認(rèn)為,class就是type,type就是class;
subclass就是subtyping,subtyping就是subclass(其實(shí)這句不嚴(yán)謹(jǐn),在c++里可以使得subclass不是
subtyping,但是java里就沒辦法了);而dynamic type則認(rèn)為類型和class沒有關(guān)系,類型取決于一個(gè)對(duì)象能夠接受的消息。
那么哪個(gè)才是面向?qū)ο笾婷材兀窟z憾的說,static type并不是最初的面向?qū)ο蟆R詫?duì)象作為模塊化的單位,始自Simula
67。但是Simula
67并不是一個(gè)面向?qū)ο笙到y(tǒng),以目前的觀點(diǎn)來看,充其量是Object-based,第一個(gè)面向?qū)ο笳Z言當(dāng)推Smalltalk,Smalltalk是
dynamic type的。不過Smalltalk不太流行,第一個(gè)大面積流行的面向?qū)ο笳Z言是C++,C++是static
type的,正如Lisp是第一個(gè)函數(shù)式編程語言,很多Lisp的特性被當(dāng)作函數(shù)式語言的共有特性(比如表是最重要的數(shù)據(jù)結(jié)構(gòu),輕語法)一樣,所以很多人
以為面向?qū)ο缶捅厝皇莝tatic type(比如老莊和我)。對(duì)于面向?qū)ο蟮恼`解,80%來自C++。也就是說,80%來自于static
type的面向?qū)ο笙到y(tǒng)。將static type面向?qū)ο髿w咎于整個(gè)面向?qū)ο螅逸厡?shí)在是大而無當(dāng)言過其實(shí)。
后面我再一一將老莊所言之OO不當(dāng)之處加以說明
第1 關(guān)于"接口"
關(guān)于接口的問題老莊說對(duì)了,這個(gè)東西并不屬于面向?qū)ο蟮母拍睿以趧?dòng)態(tài)類型面向?qū)ο笳Z言(比如Ruby, Smalltalk里),根本沒有這個(gè)東西。這是一個(gè)純粹的靜態(tài)類型面向?qū)ο笳Z言的特性,或者直接說,接口就是一個(gè)純類型(Type)。還是上次的例子:
1


interface Instrument

{
2

void playNote(Note note);
3

void playChord(Chord chord);
4

}
5

6

in Person Class
7

8


void playSolo(Instrument instrument)

{
9

10

}
在我接觸Smalltalk的最開始的一段時(shí)間里,這種地方是讓我最難受,我已經(jīng)習(xí)慣了用類型輔助我的思維,但是我發(fā)現(xiàn)我在Smalltalk里做不到,雖然我可以寫出

Instrument>>playNote:note

^self subclassResponsibility.


Instrument>>playChord:chord

^self subclassResponsibility.
但是他卻不是一個(gè)接口,我可以很用

instrument = Instrument new.

instrument playNote: Note C.
來構(gòu)造一個(gè)Instrument之后在它之上調(diào)用playNote方法,然而我會(huì)得到一個(gè)messageNotUnderstand的錯(cuò)誤,
Smalltalk和Ruby里沒有Abstract的概念。也就是說abstract method,abstract
class以及interface,都不是面向?qū)ο蟮母拍睿ɑ蛘邍?yán)格一些說,都不是面向?qū)ο蟮谋仨毜母拍睿敲嫦驅(qū)ο箢愋拖到y(tǒng)的概念。那么在
Smalltalk里我們會(huì)怎么做呢?

Person>>playSoloOnInstrument:instrument

instrument playNote: Note C;

playNote: Note D;

playNote: Note E.


Person>>playBackgroundOnInstrument:instrument

instrument playChord: Chord C1;

playChord: Chord C1;

playChord: Chord C1;
對(duì)于playSoloOnInstrument:instrument,我們對(duì)于instrument的類型是有要求的,就是它必須能夠接受playNote這個(gè)消息。當(dāng)然這個(gè)類型需要是隱性,我也可以對(duì)等的寫出靜態(tài)面向?qū)ο蟮拇a把這個(gè)隱性的類型顯示的表示出來:
1


interface Instrument

{
2

Instrument playNote(Note note);
3

}
同樣對(duì)于第二個(gè)方法我們也可以寫出來:
1


interface Instrument

{
2

Instrument playChord(Note note);
3

}
如果我們需要多于一個(gè)的消息也是一樣的,比如

Person>>playBWV996OnInstrument:instrument

instrument playNote: Note C;

playChord: Chord C;

playNote: Note D.
同樣這個(gè)時(shí)候隱性的類型需要就是
1


interface Instrument

{
2

Instrument playNote(Note note);
3

Instrument playChord(Note note);
4

}
那么接口是什么呢?我給出一個(gè)不確切的說法, interface是一個(gè)消息的發(fā)送者(sender)和一個(gè)消息的接受者(reciver)間的一種類型的約定 ,
也就是說在我看來interface的用處主要在細(xì)粒度的顯式類型約定。我有一個(gè)同事,每次寫代碼都為一個(gè)Test
Case所要測(cè)試的對(duì)象定義一個(gè)interface,每個(gè)interface都只有2-3個(gè)方法(lx同學(xué)夸你呢:D),這是很得interface之三
味的用法。這種的做法對(duì)于在靜態(tài)的面向?qū)ο笙到y(tǒng)的好處我們?cè)诶^承里再論述。
至于老莊所說的接口是多繼承的一種代替品,這只不過是世俗的看法,在靜態(tài)類型的面向?qū)ο罄铮^承至少有2個(gè)語義:
1.實(shí)現(xiàn)繼承,這個(gè)在Smalltalk,Ruby,C++里有,而在java里沒有,C++里是通過private extends來實(shí)現(xiàn)的
1


class SubClassA: private ImplementationParent

{
2

}
這也是C++里為數(shù)不多的subclass不是subtype的例子。
2.類型繼承,這個(gè)在C++和java里有,而在smalltalk,ruby有卻不明顯。
類型繼承的極致就是C++里的純虛父類
1


abstract class Parent

{
2

3

public asbtract void method1() = 0;
4

public asbtract void method2() = 0;
5

}
也就是java里的interface
1


interface Parent

{
2

void method1();
3

void method2();
4

}
因此,也就明了了,所謂“面向接口編程”是以類型作為約定的編程。我覺得這點(diǎn)大家一定不陌生,面向接口的編程里interface都很小而且約定明
確。但是要說明一點(diǎn)的是,這個(gè)東西和"面向抽象而不要面向具體編程"其實(shí)還不一樣,所以這個(gè)東西也就僅僅能算是靜態(tài)類型面向?qū)ο蟮囊粋€(gè)慣用法,還到不了原
則這么高。
第2 繼承
前面已經(jīng)說過了,繼承至少有2個(gè)語義: 實(shí)現(xiàn)繼承和類型繼承,在說明這兩個(gè)東西之前,我們繼續(xù)來看上面的例子

Person>>playSoloOnInstrument:instrument

instrument playNote: Note C;

playNote: Note D;

playNote: Note E.


Person>>playBackgroundOnInstrument:instrument

instrument playChord: Chord C1;

playChord: Chord C1;

playChord: Chord C1;


Person>>playBWV996OnInstrument:instrument

instrument playNote: Note C;

playChord: Chord C;

playNote: Note D.
現(xiàn)在我們看playBWV996這個(gè)消息,BWV996是Bach所寫一個(gè)魯特琴組曲,魯特琴是彈撥樂器,同時(shí)也是和聲樂器(所謂和聲樂器就是可以演奏和聲)。在很多樂器上都有改編的版本,比如魯特琴的近親吉他等等,這個(gè)時(shí)候,我們可以實(shí)現(xiàn)這樣幾個(gè)類
然后我們可以嘗試以此調(diào)用

vincent.playBWV996OnInstrument: Guitar new.

vincent.playBWV996OnInstrument: Lute new.

vincent.playBWV996OnInstrument: Bass new.
最后一個(gè)會(huì)得到一個(gè)messageNotUnderstand的錯(cuò)誤。也就是說,對(duì)于Bass而言由于不能演奏和聲從而不能演奏BMV996(不過這個(gè)世界上能人太多了...哎),我們換到靜態(tài)類型面向?qū)ο笙到y(tǒng)來看。
對(duì)于第一個(gè)方法,playSolo的時(shí)候我們要求的類型是能夠演奏單音的。我們可以寫出來
1


interface SoloInstrument

{
2

SoloInstrument playNote(Note note);
3

}
對(duì)于第二個(gè)方法,playChord的時(shí)候我們要求的類型是能夠演奏和弦的,我們可以寫出來
1


interface ChordInstrument

{
2

ChordInstrument playChord(Chord note);
3

}
而對(duì)于第三個(gè)方法,playBWV996的時(shí)候我們要求既能演奏和弦也能演奏單音,這個(gè)時(shí)候出現(xiàn)一個(gè)問題,我們?cè)趺刺幚鞩nstrument的繼承關(guān)系?一個(gè)能演奏和弦的樂器是否可以演奏單音(答案是一般而言是的,但是也不排除有一些不是這樣的)?還是我們簡(jiǎn)單的寫:
1


interface SoloAndChordInstrument extends SoloInstrument, ChordInstrument

{
2

}
或者
1


interface BWV996Playable

{
2

3

BWV996Playable playNote(Note note);
4

BWV996Playable playChord(Chord note);
5

}
對(duì)于動(dòng)態(tài)類型簡(jiǎn)單的隱性類型約定,顯示的類型系統(tǒng)帶來的一個(gè)副作用就是我們必須處理類型之間的關(guān)系。 注意這里是類型之間的關(guān)系,而不是對(duì)象之間的關(guān)系 。老莊同志批了很多篇的面向?qū)ο蟮某橄螅嫦驅(qū)ο蟮念愋拖到y(tǒng)以及面向?qū)ο蟮谋倔w論, 其實(shí)都在是在類型關(guān)系上折騰,而不是在對(duì)象關(guān)系上折騰 。而事實(shí)上面向?qū)ο蟮?strong> 類型系統(tǒng)并非必然就是靜態(tài)類型系統(tǒng),而我們的類之間的關(guān)系不一定就和類型的關(guān)系相一致。 就像上例所示,在Smalltalk里,Lute,Guitar和Bass之間沒有任何的繼承關(guān)系,但是對(duì)于person的3個(gè)消息而言,它們卻是有類型的。
因此老莊所批的,是對(duì)象類型系統(tǒng)的抽象能力,而非面向?qū)ο蟮某橄竽芰ΑU缢陬愋拖到y(tǒng)里所給的例子,那張他認(rèn)為很失敗的面向?qū)ο蟮膱D,其實(shí)可以完全不依賴?yán)^承來實(shí)現(xiàn),而對(duì)這個(gè)類型系統(tǒng)的消費(fèi)者而言,他們能夠以一定的類型的觀點(diǎn),來處理這個(gè)系統(tǒng)的對(duì)象。
而老莊最后一個(gè)結(jié)論:

我的結(jié)論是:“一個(gè)類型,是由其本質(zhì)決定了所能表現(xiàn)出的可操作性,而不是有其所能接受的操作決定了其本質(zhì)。然而,OO正好把這個(gè)問題搞反了!”
我的看法是,這句話根本就是詭辯,前面半句的主語是“一個(gè)類型”,后面半句的主語是"OO"...
雖然前半句是對(duì)的,但是換一樣說法可能更好:" 所能接受的操作反映了其本質(zhì) ",
面向?qū)ο蟊旧砭蜎]有說我要做一個(gè)本質(zhì)抽象,這一點(diǎn)在Smalltalk的類型判斷操作上的可能是一個(gè)佐證,Smalltalk用isKindOf來判斷繼
承關(guān)系,我們來玩一個(gè)文字游戲,改成俚語就是kinda,也就是"有一點(diǎn),有幾分"的意思,而不是說,“就是”,或者“從分類學(xué)上可證明之類的含義”。我
再舉一個(gè)齷齪的例子。

vincent ballon: AirBallon new.

vincent ballon: Condom new.
氣球和保險(xiǎn)套,對(duì)于ballon這個(gè)方法而言是一個(gè)類型,都是"有幾分"可以吹起來。但是我怎么定義一個(gè)精確的本質(zhì)?Ballonable?還是MakeFromLatexAndVeryThin?或者簡(jiǎn)單說FlexableAndThin?
在繼承這一點(diǎn)上,我想老莊引文中:Elminster的話是從事物的特征與屬性歸納出它的“類型”。恰恰對(duì)于靜態(tài)類型面向?qū)ο笙到y(tǒng)是可行的。如我前
文所述,我把一個(gè)object和所有sender的約定(也就是interface),繼承在一起,恰恰就是一個(gè)頗為恰當(dāng)?shù)念愋投x。
而對(duì)于動(dòng)態(tài)類型系統(tǒng)里的面向?qū)ο笳Z言,繼承的也有類型繼承的含義,但是并不是唯一的途徑。用一句我們常說的話,在靜態(tài)類型系統(tǒng)里,類型和類是緊耦合的,動(dòng)態(tài)類型系統(tǒng)中他們的耦合比較松。
從此而觀,所有對(duì)于面向?qū)ο蟮恼軐W(xué)考慮以及本體的思考,對(duì)于動(dòng)態(tài)面向?qū)ο笙到y(tǒng)已經(jīng)不是那么迫切了。而把對(duì)象類型系統(tǒng)的不足歸咎于面向?qū)ο蟮牟蛔悖菜坪跽摀?jù)不足。
第3. 一切皆對(duì)象和面向?qū)ο蟮睦碚摶A(chǔ)
老莊是反對(duì)一切皆對(duì)象的,而TrustNo1在javaeye的一篇帖子上說:

第一,我可以很負(fù)責(zé)的說,OO的,70年代成型,80年代在理論基礎(chǔ)上就給人斃掉。從這種意義上說不是OO死不死的問題,而是OO還活著么?當(dāng)然理論基礎(chǔ)給人斃掉,不是說沒有用。
我先說面向?qū)ο蟮睦碚摶A(chǔ)的問題,至于一切皆對(duì)象稍后再表。
所謂面向?qū)ο蟮睦碚摶A(chǔ)其實(shí)是沒有的,原因很簡(jiǎn)單,面向?qū)ο蟾揪筒皇?
一種計(jì)算模型。在第一次軟件危機(jī)的那個(gè)時(shí)代,對(duì)與計(jì)算機(jī)的非數(shù)值計(jì)算應(yīng)用的討論以及對(duì)于可計(jì)算性問題的研究和發(fā)展,大抵確立了幾種主流的計(jì)算模型:遞歸函
數(shù)類,圖靈機(jī),Lambda演算,Horn子句,Post系統(tǒng)等等。
其中遞歸函數(shù)類是可計(jì)算性問題的數(shù)學(xué)解釋;圖靈機(jī)是圖靈解決可計(jì)算問
題的時(shí)候所設(shè)計(jì)的裝置,其后成為計(jì)算機(jī)的裝置模型,與圖靈機(jī)相關(guān)的形式語言和自動(dòng)機(jī)成為了命令式語言的理論基礎(chǔ);lambda演算成為了函數(shù)式語言的理論
基礎(chǔ);Horn子句是prolog這類邏輯語言的理論基礎(chǔ)。但是我們驚訝的發(fā)現(xiàn),面向?qū)ο鬀]有計(jì)算模型的理論基礎(chǔ),換而言之,面向?qū)ο蟾揪筒皇菑目捎?jì)算
性的研究上發(fā)展過來的,那么面向?qū)ο蟮睦碚摶A(chǔ)的價(jià)值本身就不大。
所以我很奇怪的一個(gè)問題就是TrustNo1所謂的面向?qū)ο笤?0年代理論基礎(chǔ)上給人斃掉的說法是從何而來的?既然面向?qū)ο蟊举|(zhì)上不是一種計(jì)算模
型,那么它大抵上只能歸結(jié)為一種應(yīng)用技術(shù),應(yīng)用技術(shù)自然可以從各種不同的領(lǐng)域里得到相似的應(yīng)用,那么斃掉的理論基礎(chǔ)所指的又是什么呢?甚怪之。
既然面向?qū)ο蟛皇且粋€(gè)計(jì)算模型,那么我們可以從不同的角度推斷出OO的各種形態(tài),老莊已經(jīng)出給了從ADT引出OO的問題以及例子,我就不羅嗦了,我
給一個(gè)從Functional Programming出來的例子,其實(shí)就是SICP里的Data as Procedure。

(define (make-user name age sex)

(define (dispatch message)

(cond ((eq? message 'getName) name)

((eq? message 'getAge) age)

((eq? message 'getSex) sex))

(else (error 'messageNotUnderstand))))

dispatch)
然后我們就可以

(define vincent (make-user 'Vincent 24 'Male))

(vincent 'getName)
自然的,如果我調(diào)用

(vincent 'sayHi)
會(huì)得到一個(gè)messageNotUnderstand的runtime錯(cuò)誤,這就是一個(gè)很自然dyanmic
type的對(duì)象封裝,最早的面向?qū)ο笙到y(tǒng)Smalltalk和CLOS基本上都是這個(gè)路子,于是有一個(gè)問題,為什么最早的面向?qū)ο笙到y(tǒng)都是dyanmic
type?這里就跟lambda演算有關(guān)了。
lambda演算這個(gè)計(jì)算模型根本的一個(gè)假設(shè)就是,對(duì)于任何一個(gè)定義良好的數(shù)學(xué)函數(shù),我都可以使用lambda抽象來表述他的求值,因此無論是什么
東西你能夠構(gòu)造lambda抽象的話,我就能計(jì)算。這個(gè)地方東西很多,大家可以找找lambda演算相關(guān)的資料,這里我說三件事(由于lambda太難輸
入,我用scheme程序代替,然后由于alpha變化,beta規(guī)約和eta規(guī)約我也用scheme偽碼來模擬。)
第一個(gè)是數(shù)值的表述,其實(shí)這個(gè)很簡(jiǎn)單,不考慮丘奇代數(shù)的系統(tǒng)的話,我們可以把數(shù)值表示成單值函數(shù):

(define one (lambda (x) 1))
這個(gè)東西無論給什么x都返回1,然后根據(jù)lambda演算里的alpha變換,這個(gè)lambda抽象等價(jià)于數(shù)值1。因此,對(duì)于所有的數(shù)值,我們可以按lambda演算處理。
第二個(gè)是bool的表達(dá),也就是如何邏輯進(jìn)行l(wèi)ambda抽象,下面我直接給出了,缺省認(rèn)為大家都看了SICP,對(duì)Scheme也頗有心得。

(define true-new (lambda (x y) x)) ;;;這個(gè)函數(shù)也叫select-first

(define false-new (lambda (x y) x));;;這個(gè)函數(shù)也叫select-second


(define if-new (lambda (conditon if-true if-false) (condition if-true if-false)))
然后我就可以做一個(gè)測(cè)試

(if-new true-new 3 4)

3


(if-new false-new 3 4)

4
因此,對(duì)于所有bool我們可以按lambda演算來處理
第三個(gè)是自定義類型,這里我們還是先看一個(gè)Lisp里的例子,序?qū)Α?/p>

(define (cons a b) (lambda (dispath) (dispatch a b)))

(define (car list) (list select-first))

(define (cdr list) (list select-second))
這里依舊是high-order,我們來測(cè)試

(define list1 (cons 1 2))

(car list1)

1

(cdr list1)

2
這里大家自己用beta規(guī)約算一下,就發(fā)現(xiàn)的確是這樣的。這里我們又可以看到,在lambda演算里,根本沒有數(shù)據(jù)或者類型。有的永遠(yuǎn)各種各樣的
lambda抽象而已(目前已經(jīng)有了帶類型的lambda演算)。這里說一句題外話,SICP里的Data as
Procedure其實(shí)就是在說這個(gè)問題,不過他沒明說,而是用了一種特殊的用法而引出了消息傳遞風(fēng)格,我覺得這里SICP有些顧此失彼,對(duì)于data
as procedure我總結(jié)的一般形式是

(define (construct-function value1 value2 value3 value4

valuen) (lambda (dispatch) (dispatch value1 value2 value3 value4

valuen)))

(define (select-function1 data) (data select-first))

(define (select-function2 data) (data select-second))


.

(define (select-functionn data) (data select-last))
綜上所述,我們看到在lambda演算里,一切都是lambda抽象,然后對(duì)于不同的lambda抽象使用alpha變換,beta規(guī)約和eta規(guī)約,表述各種不同計(jì)算。看,在面向?qū)ο笾熬鸵呀?jīng)有了一切皆某某的完美的計(jì)算理論存在了。而且回顧一下:

(define (make-user name age sex)

(define (dispatch message)

(cond ((eq? message 'getName) name)

((eq? message 'getAge) age)

((eq? message 'getSex) sex))

(else (error 'messageNotUnderstand))))

dispatch)


(define vincent (make-user 'Vincent 24 'Male))

(vincent 'getName)
我們有理由說,對(duì)象其實(shí)就是一個(gè)lambda抽象,所以一切皆對(duì)象不過是一切皆lambda抽象的演化,這也是為什么SICP里把面向?qū)ο蠓Q作一種“方便的界面”而不是一種抽象的方法的原因了。那么對(duì)象和lambda抽象又什么區(qū)別呢?
嘿
嘿,熟悉FP的人都應(yīng)該知道了,就是Side-Effect,副作用。對(duì)象允許對(duì)其內(nèi)部狀態(tài)進(jìn)行修改,那么這個(gè)東西就破化了eta規(guī)約的前提條件,也就是
說允許修改內(nèi)部狀態(tài)的東西,已經(jīng)不是一個(gè)可以進(jìn)行l(wèi)ambda計(jì)算的lambda抽象了。因此暫且給一個(gè)別的名字吧,就叫對(duì)象吧.....因此我認(rèn)為,對(duì)
象很大程度上是一種帶有副作用的lambda抽象。
我在有一篇blog上寫了Say sorry to
object-oriented,里面給了一只用對(duì)象作分支的例子,這里就不重復(fù)了,有興趣大家可以去看一下(剛才好像在JavaEye上看到一個(gè)說法,
說Everything is Object是Smalltalk的廣告語,唉,Smalltalk里的的的確確everything is
object啊。)
這里我們來總結(jié)一下,面向?qū)ο笞鳛橐环N“方便的界面”主要解決了一個(gè)局部化和模塊化的問題,這是從lambda演算和
函數(shù)編程的角度來看面向?qū)ο蠹夹g(shù)。(taowen在他的一篇blog上說,面向?qū)ο缶植炕薙ide-Effect,我深以為然),這個(gè)東西我個(gè)人認(rèn)為更
加接近面向?qū)ο蟊緛淼囊馑迹皇怯葾DT里發(fā)展出來的帶類型的對(duì)象系統(tǒng)的那個(gè)意思。因此老莊不以為然的面向?qū)ο箢愋拖到y(tǒng),我也不以為然。但是面向?qū)ο笞?
為lambda抽象的界面,我覺得還是很不錯(cuò)的。這一點(diǎn)在Smalltalk和Ruby里都有不錯(cuò)的體現(xiàn)。