摘要:因為是一種長程的關(guān)聯(lián),基類的修改對繼承者的影響難以估計和維護,具有特性,因此從耦合度的角度說,它大大提高了組件的耦合度,高耦合度不是罪過,但它應(yīng)對變化的能力變差了。
JavaScript開發(fā)者的繁殖速度和它的語言特性一樣迅猛,這是好事,但是也把JS搞得比任何一種其他語言都更像流行樂,充滿教派和玄學(xué)。但編程不是玄學(xué),是科學(xué)和工程。這篇文章就用來闡述和探討JavaScript中的一個比較關(guān)鍵的概念,雖然在實踐上并不如在理論上那么意義重大。
Prototype Inheritance是JavaScript里的一個標(biāo)志性特性。實際上它叫做Inheritance是有一些問題的,JS沒有type系統(tǒng),instanceof也只是一個沿著原型鏈查找constructor的語法糖,一個對象是誰構(gòu)造出來的并不說明任何問題,因為它的對象沒有結(jié)構(gòu)上的穩(wěn)定性承諾,只能靠程序員自覺。
Inheritance是OO近30年的工程實踐里留下來的重要特性,但是它不是一個好的特性。當(dāng)然好與不好是相對的,在絕大多數(shù)情況下它都不是太大的問題,尤其是工程進入尾聲,開發(fā)者對問題和模型有充分認識的時候,Class Hierarchy可以是很合理的設(shè)計。
那么,在更General的層面上去問Inheritance設(shè)計解決的是什么問題呢?兩個字,reuse。
在Java里,reuse有兩個語法關(guān)鍵字,一個是extends,即inheritance,另一個是implements,實現(xiàn)interface。
那么為什么把implements也當(dāng)成reuse呢?因為任何模塊總有兩個方面,使用者和提供者,implements實現(xiàn)了一個interface,所以等價于重用了使用者代碼。
當(dāng)然你說extends也達到了同樣的目的呀?而且我還重用了父類的狀態(tài)和行為呢?是的,凡是兩面,有得有失;這正是它倒霉的地方。
它倒霉的具體情況被稱為fragile base class問題,wiki上有詞條,不贅述。
因為extends/inheritance是一種長程的關(guān)聯(lián),基類的修改對繼承者的影響難以估計和維護,具有ripple effect特性,因此從耦合度的角度說,它大大提高了組件的耦合度,高耦合度不是罪過,但它應(yīng)對變化的能力變差了。
好了,說了這么多我們說到了問題的本原。
在Self語言中,也是最早試圖解決這個問題的語言設(shè)計者們,給出了Prototypal Inheritance設(shè)計,
它的設(shè)計初衷有兩個:
抹平Class和Object的差異,讓修改基類變得容易;
如果你修改基類,復(fù)制一個基類對象然后修改,新繼承者從新的基類對象開始繼承。其他繼承者不受影響。
你覺得這個差別很重要嗎?其實在實踐上沒有想象的那么重要。
JavaScript在設(shè)計上還有點不同,它的原型對象是共享而非復(fù)制的,結(jié)果是只適合把方法裝載到原型上去,偶爾有一些同類對象相同的只讀context也可以這樣做,其他每對象私有態(tài)還得通過調(diào)用父類構(gòu)造函數(shù)做出來,即ES6里的super關(guān)鍵字,如果是ES5,得手動把this bind到父類構(gòu)造函數(shù)上調(diào)用。這個特性就語言而言是重要特性,但是和我們討論的問題沒太大關(guān)系。
更重要的問題出在設(shè)計上而不是語言層面。
James Gosling在一次研討會上回答問題時,有人問了他這樣一個問題,如果重新設(shè)計Java語言,他會有什么重要的取舍。Gosling的回答可能有點兒令你吃驚:他說如果可以重新來過,他不會賦予Java語言繼承特性,只用implements。
呃?!
其實是可以理解的。
繼承設(shè)計看起來在代碼重用上很方便,但是它的fragile base class問題,讓它無法應(yīng)對軟件系統(tǒng)的scale問題。這一點不用論證,在整個軟件工業(yè)上,繼承這種whitebox reuse不能scale是一個定論,單一程序用繼承書寫代碼不是問題,但是任何有點規(guī)模的系統(tǒng)都是靠interface,protocol,或者所謂的component-based工程方法來搭建的,也就是在更高粒度的設(shè)計層面只有基于Interface的blackbox reuse。
在任何語言中,都能用blackbox reuse構(gòu)建復(fù)雜系統(tǒng)。在JavaScript中,龐大的npm包系統(tǒng)實現(xiàn)的最終應(yīng)用,也是blackbox reuse。
JavaScript本身是否functional是洗剪吹們喜歡探討的,嚴(yán)肅的工程師不該干這個事兒;但是整個JavaScript的Community的共識是基于blackbox reuse構(gòu)建系統(tǒng),這是好事。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
那么是否該使用extends呢?
很多時候沒什么必要性。既然Gosling都說不該去通過inheritance-based hierarchy去組合復(fù)雜行為(犧牲低耦合度),誰還比他更有資格對這個問題發(fā)言呢?
通常可以把幾個邏輯單元糖葫蘆一樣串起來實現(xiàn)一個從外部看來功能特別Powerful的一個對象時,也很容易把每個獨立單元用decorator,facade之類的pattern串起來,可能會多寫點兒代碼,但不會很多,JavaScript作為無類型動態(tài)語言在書寫pattern時具有顯著的簡潔優(yōu)勢。(在C++/Java里是相反的,只寫inheritance顯著比寫pattern簡潔;但是問題就是問題你無法回避,如果必須要松開耦合,還得回到pattern上定義,這也是為什么這些pattern被發(fā)明出來的原因。)
當(dāng)然用extends方便的時候也沒必要去抵觸它,比如node里的event emitter,stream等等,該用就用唄,只要不去試圖構(gòu)造framework一樣的hierarchy即可。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果有人跟你說JavaScript不是OO語言,請一腳把它踹溝里去,JS里除了用Object Literal寫出來的ex nihilo對象之外,(邏輯上)所有對象都是用構(gòu)造函數(shù)構(gòu)造出來的,這甚至包括全局的Object, Array,F(xiàn)unction等等,一切皆對象是JS的最高設(shè)計思想。你怎么能說它不是OO的?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/86529.html
摘要:首先,需要來理清一些基礎(chǔ)的計算機編程概念編程哲學(xué)與設(shè)計模式計算機編程理念源自于對現(xiàn)實抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機制一直以來都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因為絕大多數(shù)人沒有想要深刻理解這個機制的內(nèi)涵,以及越來越多的開發(fā)者缺乏計算機編程相關(guān)的基礎(chǔ)知識。對于這樣的開發(fā)者來說 J...
摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語言之一,而演算則可以說是孕育了這門語言。即使在今天,這個家族的編程語言應(yīng)用范圍依然很廣。 1. 能說出來兩種對于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門多范式(multi-paradigm)的編程語言,它既支持命令式(imperative)/面向過程(procedural)編程...
摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語言之一,而演算則可以說是孕育了這門語言。即使在今天,這個家族的編程語言應(yīng)用范圍依然很廣。 1. 能說出來兩種對于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門多范式(multi-paradigm)的編程語言,它既支持命令式(imperative)/面向過程(procedural)編程...
摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語言之一,而演算則可以說是孕育了這門語言。即使在今天,這個家族的編程語言應(yīng)用范圍依然很廣。 1. 能說出來兩種對于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門多范式(multi-paradigm)的編程語言,它既支持命令式(imperative)/面向過程(procedural)編程...
閱讀 2732·2023-04-25 14:21
閱讀 1167·2021-11-23 09:51
閱讀 3999·2021-09-22 15:43
閱讀 605·2019-08-30 15:55
閱讀 1550·2019-08-29 11:28
閱讀 2438·2019-08-26 11:44
閱讀 1675·2019-08-23 18:15
閱讀 2874·2019-08-23 16:42