官术网_书友最值得收藏!

1.2 Java編程風格的主觀歷史

像古代詩人一樣,我們把Java編程的發展分為4個不同的風格時期——原始風格、Bean風格、企業風格和現代風格。

1.2.1 原始風格

Java最初用于家電和交互式電視等領域,直到Netscape在其廣受歡迎的Navigator瀏覽器中采用Java applet后,Java才開始流行。Sun公司發布了JDK(Java開發工具包)1.0,隨著微軟在IE瀏覽器中加入了Java,一瞬間,每個擁有Web瀏覽器的人都擁有了Java運行環境。人們對Java編程語言的興趣激增。

此時,Java的基礎已經奠定:

? Java虛擬機及其字節碼和類文件格式。

? 原始類型和引用類型、空引用、垃圾回收。

? 類、接口、方法和控制流語句。

? 用于錯誤處理的檢查異常和抽象的視窗化工具箱。

? 用于與互聯網和網絡協議聯網的類。

? 代碼在運行時的加載和鏈接,由安全管理器進行沙箱管理。

然而,Java還沒有準備好支持通用編程:JVM的運行速度很慢,標準庫稀少。

Java看起來像是C++和Smalltalk的混合品,這兩種語言影響了當時的Java編程風格。備受其他語言程序員嘲笑的“getFoo/setFoo”和“AbstractSingletonProxyFactoryBean”約定還沒有普及。

Java的一項無名創新是一種官方編碼約定,它規定了程序員應該如何命名包、類、方法和變量。C和C++程序員遵循著看似無限多樣的編碼約定,而在將多個庫組合在一起時,代碼最終看起來卻有些雜亂不一致。Java唯一的編碼約定是Java程序員可以將陌生人的庫無縫地集成到自己的程序中,這推動了一個生機勃勃的開源社區的發展,這個社區一直持續到今天。

1.2.2 Bean風格

在Java取得初步的成功之后,Sun公司開始將其作為構建應用程序的實踐工具。Java 1.1(1996)添加了新的語言特性(最顯著的是內部類),改進了運行時的主要特性(最顯著的是即時編譯和反射),并擴展了標準庫。Java 1.2(1998)添加了標準的Collections API和跨平臺GUI框架Swing,這確保了Java應用程序在每個桌面操作系統上看起來和感覺都是一樣的笨拙。

此時,Sun公司正緊盯著微軟和Borland在企業軟件開發方面的主導地位。Java有可能成為Visual Basic和Delphi的有力競爭者。受Microsoft API的啟發,Sun添加了大量的API:用于數據庫訪問的JDBC(相當于Microsoft ODBC)、用于桌面GUI編程的Swing(相當于Microsoft MFC)以及對Java編程風格影響最大的框架JavaBeans。

JavaBeans API是Sun公司對Microsoft ActiveX組件模型的回應,用于低代碼、圖形化和拖放式編程。Windows程序員可以在其Visual Basic程序中使用ActiveX組件,或將其嵌入公司內網上的Office文檔或網頁中。盡管ActiveX組件的使用非常簡單,但它們非常難寫。JavaBeans要容易得多,你只需遵循一些額外的編碼約定,就可以將Java類視為可以在圖形設計器中實例化和配置的Bean。“一次編寫,隨處運行”的承諾意味著你能夠在任何操作系統上使用JavaBean組件,而不僅僅在Windows上。

一個類如果想要成為JavaBean,需要有一個不帶參數的構造函數,可序列化,并聲明一個API,API中包括一組可讀且部分可寫的公共屬性、可調用的方法以及該類對象所發出的事件。這樣,程序員就可以在圖形化的應用程序設計器中實例化Bean,通過設置屬性來配置它們,并將Bean發出的事件連接到其他Bean的方法上。默認情況下,Bean API通過以get和set開頭的一對方法定義其屬性。這種默認的方式可以被重寫,但這樣做需要程序員編寫更多的模板代碼類。程序員通常只是改造現有的類,使其成為JavaBean時才會這么做。在新的代碼中遵循JavaBean的“紋理”會讓你的工作容易得多。

Bean風格的缺點在于它很大程度上依賴于可變的狀態,并且要求有比POJO(Plain Old Java Object,普通舊Java對象)更多的公開狀態,因為可視化構建工具不能向對象的構造函數傳遞參數,而是必須設置其屬性。Bean用于用戶界面組件表現良好,因為可以用默認的內容和樣式安全地初始化它們,并在構造后進行調整。當一些類沒有設置合理的默認值時,以同樣的方式處理它們很容易出錯,因為類型檢查器不能告訴我們Bean所需的值是否已全部提供。Bean約定使編寫正確的代碼變得更加困難,而且依賴項的修改會悄無聲息地破壞調用端代碼。

最終,JavaBean的圖形化組合并沒有成為主流,但它的編碼約定流傳了下來。Java程序員遵循JavaBean約定,即使他們并不打算將自己的類用作JavaBean。Bean對Java編程風格產生了巨大的、持久的但并不完全是積極的影響。

1.2.3 企業風格

Java最終在企業中傳播開來。它并沒有像預期的那樣取代企業桌面上的Visual Basic,而是取代了C++,成為服務器端的首選語言。1998年,Sun公司發布了Java 2企業版(當時稱為J2EE,現在稱為JakartaEE),這是一套用于編寫服務器端事務處理系統的標準API。

J2EE API存在抽象反轉問題。JavaBeans和applet API也存在抽象反轉問題,例如,它們都不允許將參數傳遞給構造函數,但在J2EE中問題更為嚴重。J2EE應用程序沒有單一的入口點。它由很多小組件組成,其生命周期由應用程序容器管理,并通過JNDI名稱服務互相暴露。應用程序需要大量的模板代碼和可變的狀態來查找它們所依賴的資源。程序員發明了依賴注入(D I)框架來應對這個問題,這些框架可以完成所有資源的查找和綁定,并管理生命周期。其中最成功的是Spring。它建立在JavaBeans的編碼約定之上,并使用反射來組成類似Bean對象的應用程序。

抽象反轉

抽象反轉是一種架構上的缺陷,即軟件平臺阻止調用端代碼使用它所需要的底層機制。這就迫使程序員使用平臺API所暴露的高層設施來重新實現這些底層機制,而這些設施又使用了被重新實現的功能。其結果是不必要的代碼、糟糕的性能以及額外的維護和測試成本。

以J2EE Servlet為例。在Servlet API中,負責實例化Servlet對象的是Servlet容器,而不是Web應用程序。而事實上,Web應用程序根本不是用Java寫的,它是一個XML文件,列出了Servlet容器需要實例化的類。因此,每個Servlet都必須有一個無參構造函數,而Web應用程序無法通過將對象傳遞給其構造函數來初始化Servlet。

相反,你必須編寫一個ServletContextListener來創建應用程序Servlet所需的對象,并將其存儲為ServletContext的具名、非類型化屬性:

Servlet通過在上下文中尋找它們所需要的對象并將其轉換為預期的類型來初始化自身:

如果Servlet API沒有阻止你這樣做,這比調用構造函數所付出的代價要大得多。而且構造函數的調用會進行類型檢查。難怪Java程序員會發現依賴注入框架是一種進步。

在Servlet API首次發布的20多年后,Servlet API終于在3.0版本中允許Web應用程序實例化Servlet并將依賴關系傳遞給其構造函數。

在編程風格方面,DI框架鼓勵程序員避免直接使用new關鍵字,而是依靠框架來實例化對象。Android的API也表現出抽象反轉,Android的程序員也轉向DI框架幫助他們編寫API。DI框架專注于面向機制而非領域進行建模的方式導致了大量的企業級類名,如Spring中臭名昭著的AbstractSingletonProxyFactoryBean。

不過,從好的方面來看,企業風格時期發布了Java 5,它為Java語言增加了泛型和自動裝箱特性,這是迄今為止最重要的變化。在這個時代,有賴于Maven打包約定和中央軟件庫的推動,Java社區也大量采用了開源庫。頂級開源庫的出現使得Java被大量用于關鍵業務應用開發,從而誕生了更多的開源庫,形成了一個良性循環。隨后是一流的開發工具,包括我們在本書中使用的IntelliJ IDE。

1.2.4 現代風格

Java 8給語言帶來了下一個重大變化——lambda,并對標準庫進行了重大補充。Streams API鼓勵使用函數式編程風格,在這種風格中,數據的處理是采用流來轉換不可變值實現的,而不是改變可變對象的狀態。新的日期/時間API忽略了JavaBeans對屬性訪問器的編碼約定,而遵循原始時代通用的編碼約定。

云平臺的發展意味著程序員不必將服務器部署到Java EE應用容器中。輕量級的Web應用框架讓程序員能夠編寫一個主函數來構建其應用。許多服務器端的程序員不再使用DI框架——函數和對象組合已經足夠好了,所以DI框架與時俱進地發布了極度簡化的API。由于沒有DI框架和可變狀態,就不太需要遵循JavaBeans的編碼約定。在單個代碼庫中,暴露不可變值的字段效果良好,因為IDE可以在需要時將字段即時地封裝在屬性訪問器后面。

Java 9中引入了模塊,但到目前為止,它們還沒有在JDK本身之外得到廣泛的應用。在最近的Java版本中,最令人興奮的是JDK的模塊化,以及將那些很少使用的模塊從JDK中移除,變成可選擇的擴展,例如CORBA。

1.2.5 未來

Java未來有望實現更多的功能,使現代風格更容易應用:record、模式匹配、用戶定義的值類型,以及最終將原始類型和引用類型統一到一個類型系統中。

然而,這是一項具有挑戰性的工作,需要很多年才能完成。Java從一開始就有一些根深蒂固的矛盾和邊緣場景,很難在保持向后兼容的同時將其統一成清晰的抽象。Kotlin有25年的前瞻性,而且是一張干凈的“白紙”,具有重新開始的優勢。

主站蜘蛛池模板: 尼勒克县| 贞丰县| 安西县| 武冈市| 开平市| 合阳县| 宝应县| 乳山市| 台湾省| 濉溪县| 九龙坡区| 砚山县| 新巴尔虎左旗| 科尔| 宣城市| 沅江市| 遵义市| 乌恰县| 巴马| 三原县| 尼木县| 临夏县| 澄迈县| 兰溪市| 化德县| 广南县| 台中市| 丽水市| 张家川| 若羌县| 安陆市| 兴城市| 昔阳县| 旬阳县| 深水埗区| 镶黄旗| 云南省| 扎兰屯市| 晴隆县| 隆林| 柳林县|