傳統(tǒng)的基于類的面向?qū)ο笳Z(yǔ)言的一個(gè)主要特點(diǎn)就是inheritance, subclassing和subtyping之間的密不可分的聯(lián)系。很多的面向?qū)ο笳Z(yǔ)言的語(yǔ)法,概念,就是從這三者而來(lái)的。比如說(shuō),通過(guò)subclassing, 你可以繼承父類的一些方法,而同時(shí)你又可以在子類中改寫(xiě)父類的方法。這個(gè)改寫(xiě)過(guò)的方法,通過(guò)subtyping, subsumption, 又可以從一個(gè)類型是父類的對(duì)象去調(diào)用。
但是,inheritance, subclassing, subtyping這三者并不是永遠(yuǎn)和睦相處的。在一些場(chǎng)合,這三者之間的糾纏不清會(huì)妨礙到通過(guò)繼承或泛型得到的代碼重用。因此,人們開(kāi)始注意到把這三者分離開(kāi)來(lái)的可能性。區(qū)分subclassing和subtyping已經(jīng)很常見(jiàn)了。而其它的一些方法還處于研究的階段。這一章我們將介紹這樣一些方法。
一,對(duì)象類型
在早期的面向?qū)ο笳Z(yǔ)言中(如Simula), 類型的定義是和方法的實(shí)現(xiàn)是混合在一起的。這種方式違反了我們今天已經(jīng)被廣泛認(rèn)識(shí)到的把實(shí)現(xiàn)和規(guī)范(Specification) 分離的原則。這種分離得原則在開(kāi)發(fā)是團(tuán)隊(duì)進(jìn)行的時(shí)候尤其顯得重要。
更近期一些的語(yǔ)言,通過(guò)引入不依賴于實(shí)現(xiàn)的對(duì)象類型來(lái)區(qū)分實(shí)現(xiàn)和規(guī)范。Modula-3以及其它如Java等的支持class和interface的語(yǔ)言都是采用的這種技術(shù)。
在本書(shū)中,我們開(kāi)始引入InstanceTypeOf(cell)時(shí),它代表的概念相當(dāng)有限??瓷先ィ坪踔槐硎居胣ew cell生成的對(duì)象的類型,于是,我們并不能用它來(lái)表示從其它類new出來(lái)的對(duì)象。但后來(lái),當(dāng)我們引入了subclassing, method overriding, subsumption和dynamic dispatch之后,事情變得不那么簡(jiǎn)單了。我們的InstanceTypeOf(cell)已經(jīng)可以用來(lái)表示從cell的子類new出來(lái)的對(duì)象,這些對(duì)象可以包括不是cell類定義的屬性和方法。
如此看來(lái),讓InstanceTypeOf(cell)依賴于一個(gè)具體的類似乎是不合理的。實(shí)際上,一個(gè)InstanceTypeOf(cell)類型的對(duì)象不一定會(huì)跟class cell扯上任何關(guān)系。
它和cell類的共同之處只是它具有了所有cell類定義的方法的簽名(signature).
基于這種考慮,我們可以引入對(duì)象類型的語(yǔ)法:
針對(duì)cell類和reCell類的定義:
class cell is
var contents: Integer :=0;
method get(): Integer is
return self.contents;
end;
method set(n:Integer) is
self.contents := n;
end;
end;
subclass reCell of cell is
var backup: Integer := 0;
override set(n: Integer) is
self.backup := self.contents;
super.set(n);
end;
method restore() is
self.contents := self.backup;
end;
end;
我們可以給出這樣的對(duì)象類型定義:
ObjectType Cell is
var contents: Integer;
method get(): Integer;
method set(n:Integer);
end;
ObjectType ReCell is
var contents: Integer;
var backup: Integer;
method get(): Integer
method set(n: Integer);
method restore();
end;
這兩個(gè)類型的定義包括了所有cell類和reCell類定義的屬性和方法的類型,但卻并不包括實(shí)現(xiàn)。這樣,它們就可以被當(dāng)作與實(shí)現(xiàn)細(xì)節(jié)無(wú)關(guān)的的接口以實(shí)現(xiàn)規(guī)范和實(shí)現(xiàn)的分離。兩個(gè)完全無(wú)關(guān)的類c和c’, 可以具有相同的類型Cell, 而Cell類型的使用者不必關(guān)心它使用的是c類還是c’類。
注意,我們還可以加入額外的類似繼承的語(yǔ)法來(lái)避免在ReCell里重寫(xiě)Cell里的方法簽名。但那只是小節(jié)罷了。
二,分離Subclassing和Subtyping.
在我們上一章的討論中,subtype的關(guān)系是建立在subclass關(guān)系的基礎(chǔ)上的。但如果我們想要讓type獨(dú)立于class, 那么我們也需要定義獨(dú)立于subclass的subtype.
在定義subtype時(shí),我們又面臨著幾種選擇:subtype是由類型的組成結(jié)構(gòu)決定的呢?還是由名字決定呢?
由類型的組成結(jié)構(gòu)決定的subtype是這樣的:如果類型一具有了類型二的所有需要具備的屬性和方法,我們就說(shuō)類型一是類型二的subtype.
由類型名字決定的subtype是這樣的:只有當(dāng)類型一具有了類型二的所有需要具備的屬性和方法, 并且類型一被明確聲明為類型二的subtype時(shí),我們才認(rèn)可這種關(guān)系。
而如果我們的選擇是一,那么那些屬性和方法是subtype所必需具備的呢?哪些是可有可無(wú)的呢?
由組成結(jié)構(gòu)決定的subtype能夠在分布式環(huán)境和object persistence系統(tǒng)下進(jìn)行類型匹配(譯者注:對(duì)這點(diǎn),我也不甚明了??磥?lái),紙?jiān)斓眠€是不夠)。缺點(diǎn)是,如果兩個(gè)類型碰巧具有了相同的結(jié)構(gòu),但實(shí)際上卻風(fēng)馬牛不相及,那就會(huì)造成錯(cuò)誤。不過(guò),這種錯(cuò)誤是可以用一些技術(shù)來(lái)避免的。
相比之下,基于名字的subtype不容易精確定義,而且也不支持基于結(jié)構(gòu)的subtype.
(譯者按,這里,我無(wú)論如何和作者找不到同感?;诮Y(jié)構(gòu)的subtype的缺點(diǎn)是一目了然,不過(guò)完美的避免的方法我卻看不出來(lái)。而基于名字的subtype為什么就不能精確定義呢?C++/Java/C#, 所有流行的OO語(yǔ)言都只支持基于名字的subtype, 也沒(méi)有發(fā)現(xiàn)有什么不夠靈活的地方。需要在不同名字但類似結(jié)構(gòu)的類型之間架橋的話,adapter完全可以勝任嘛!)
目前,我們可以先定義一個(gè)簡(jiǎn)單的基于結(jié)構(gòu)的subtype關(guān)系:
對(duì)兩個(gè)類型O和O’,
O’ <: O 當(dāng) O’ 具有所有O類型的成員。O’可以有多于O的成員。
但是,inheritance, subclassing, subtyping這三者并不是永遠(yuǎn)和睦相處的。在一些場(chǎng)合,這三者之間的糾纏不清會(huì)妨礙到通過(guò)繼承或泛型得到的代碼重用。因此,人們開(kāi)始注意到把這三者分離開(kāi)來(lái)的可能性。區(qū)分subclassing和subtyping已經(jīng)很常見(jiàn)了。而其它的一些方法還處于研究的階段。這一章我們將介紹這樣一些方法。
一,對(duì)象類型
在早期的面向?qū)ο笳Z(yǔ)言中(如Simula), 類型的定義是和方法的實(shí)現(xiàn)是混合在一起的。這種方式違反了我們今天已經(jīng)被廣泛認(rèn)識(shí)到的把實(shí)現(xiàn)和規(guī)范(Specification) 分離的原則。這種分離得原則在開(kāi)發(fā)是團(tuán)隊(duì)進(jìn)行的時(shí)候尤其顯得重要。
更近期一些的語(yǔ)言,通過(guò)引入不依賴于實(shí)現(xiàn)的對(duì)象類型來(lái)區(qū)分實(shí)現(xiàn)和規(guī)范。Modula-3以及其它如Java等的支持class和interface的語(yǔ)言都是采用的這種技術(shù)。
在本書(shū)中,我們開(kāi)始引入InstanceTypeOf(cell)時(shí),它代表的概念相當(dāng)有限??瓷先ィ坪踔槐硎居胣ew cell生成的對(duì)象的類型,于是,我們并不能用它來(lái)表示從其它類new出來(lái)的對(duì)象。但后來(lái),當(dāng)我們引入了subclassing, method overriding, subsumption和dynamic dispatch之后,事情變得不那么簡(jiǎn)單了。我們的InstanceTypeOf(cell)已經(jīng)可以用來(lái)表示從cell的子類new出來(lái)的對(duì)象,這些對(duì)象可以包括不是cell類定義的屬性和方法。
如此看來(lái),讓InstanceTypeOf(cell)依賴于一個(gè)具體的類似乎是不合理的。實(shí)際上,一個(gè)InstanceTypeOf(cell)類型的對(duì)象不一定會(huì)跟class cell扯上任何關(guān)系。
它和cell類的共同之處只是它具有了所有cell類定義的方法的簽名(signature).
基于這種考慮,我們可以引入對(duì)象類型的語(yǔ)法:
針對(duì)cell類和reCell類的定義:
class cell is
var contents: Integer :=0;
method get(): Integer is
return self.contents;
end;
method set(n:Integer) is
self.contents := n;
end;
end;
subclass reCell of cell is
var backup: Integer := 0;
override set(n: Integer) is
self.backup := self.contents;
super.set(n);
end;
method restore() is
self.contents := self.backup;
end;
end;
我們可以給出這樣的對(duì)象類型定義:
ObjectType Cell is
var contents: Integer;
method get(): Integer;
method set(n:Integer);
end;
ObjectType ReCell is
var contents: Integer;
var backup: Integer;
method get(): Integer
method set(n: Integer);
method restore();
end;
這兩個(gè)類型的定義包括了所有cell類和reCell類定義的屬性和方法的類型,但卻并不包括實(shí)現(xiàn)。這樣,它們就可以被當(dāng)作與實(shí)現(xiàn)細(xì)節(jié)無(wú)關(guān)的的接口以實(shí)現(xiàn)規(guī)范和實(shí)現(xiàn)的分離。兩個(gè)完全無(wú)關(guān)的類c和c’, 可以具有相同的類型Cell, 而Cell類型的使用者不必關(guān)心它使用的是c類還是c’類。
注意,我們還可以加入額外的類似繼承的語(yǔ)法來(lái)避免在ReCell里重寫(xiě)Cell里的方法簽名。但那只是小節(jié)罷了。
二,分離Subclassing和Subtyping.
在我們上一章的討論中,subtype的關(guān)系是建立在subclass關(guān)系的基礎(chǔ)上的。但如果我們想要讓type獨(dú)立于class, 那么我們也需要定義獨(dú)立于subclass的subtype.
在定義subtype時(shí),我們又面臨著幾種選擇:subtype是由類型的組成結(jié)構(gòu)決定的呢?還是由名字決定呢?
由類型的組成結(jié)構(gòu)決定的subtype是這樣的:如果類型一具有了類型二的所有需要具備的屬性和方法,我們就說(shuō)類型一是類型二的subtype.
由類型名字決定的subtype是這樣的:只有當(dāng)類型一具有了類型二的所有需要具備的屬性和方法, 并且類型一被明確聲明為類型二的subtype時(shí),我們才認(rèn)可這種關(guān)系。
而如果我們的選擇是一,那么那些屬性和方法是subtype所必需具備的呢?哪些是可有可無(wú)的呢?
由組成結(jié)構(gòu)決定的subtype能夠在分布式環(huán)境和object persistence系統(tǒng)下進(jìn)行類型匹配(譯者注:對(duì)這點(diǎn),我也不甚明了??磥?lái),紙?jiān)斓眠€是不夠)。缺點(diǎn)是,如果兩個(gè)類型碰巧具有了相同的結(jié)構(gòu),但實(shí)際上卻風(fēng)馬牛不相及,那就會(huì)造成錯(cuò)誤。不過(guò),這種錯(cuò)誤是可以用一些技術(shù)來(lái)避免的。
相比之下,基于名字的subtype不容易精確定義,而且也不支持基于結(jié)構(gòu)的subtype.
(譯者按,這里,我無(wú)論如何和作者找不到同感?;诮Y(jié)構(gòu)的subtype的缺點(diǎn)是一目了然,不過(guò)完美的避免的方法我卻看不出來(lái)。而基于名字的subtype為什么就不能精確定義呢?C++/Java/C#, 所有流行的OO語(yǔ)言都只支持基于名字的subtype, 也沒(méi)有發(fā)現(xiàn)有什么不夠靈活的地方。需要在不同名字但類似結(jié)構(gòu)的類型之間架橋的話,adapter完全可以勝任嘛!)
目前,我們可以先定義一個(gè)簡(jiǎn)單的基于結(jié)構(gòu)的subtype關(guān)系:
對(duì)兩個(gè)類型O和O’,
O’ <: O 當(dāng) O’ 具有所有O類型的成員。O’可以有多于O的成員。