日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

拼图项目动手指南

發(fā)布時(shí)間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 拼图项目动手指南 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Jigsaw項(xiàng)目將把模塊化引入Java平臺,根據(jù)原始計(jì)劃,它將在12月10日完成功能。 所以我們在這里,但是拼圖在哪里?

在過去的六個(gè)月中肯定發(fā)生了很多事情: 原型問世 ,內(nèi)部API的迫在眉睫的刪除引起了很大的騷動 , 郵件列表中充斥著有關(guān)項(xiàng)目設(shè)計(jì)決策的重要討論 ,而JavaOne看到了一系列很棒的介紹性演講 。拼圖團(tuán)隊(duì)。 然后Java 9因拼圖而延遲了半年 。

但是,讓我們暫時(shí)忽略所有這些,僅關(guān)注代碼。 在本文中,我們將使用一個(gè)現(xiàn)有的演示應(yīng)用程序并將其與Java 9進(jìn)行模塊化。如果要繼續(xù)學(xué)習(xí),請轉(zhuǎn)到GitHub ,在該處可以找到所有代碼。 設(shè)置說明對于使腳本與Java 9一起運(yùn)行很重要。為簡便起見,我從本文的所有程序包,模塊和文件夾名稱中刪除了前綴org.codefx.demo 。

拼圖之前的應(yīng)用

即使我竭盡全力不理會整個(gè)圣誕節(jié),但讓演示程序秉承本季的精神似乎是審慎的做法。 因此,它為出現(xiàn)日歷建模:

  • 有一個(gè)日歷,其中包含24個(gè)日歷表。
  • 每張紙都知道該月的某天,并包含一個(gè)驚喜。
  • 即將到圣誕節(jié)的死亡行軍是通過在控制臺上打印床單(以及由此帶來的驚喜)來象征的。

當(dāng)然,需要首先創(chuàng)建日歷。 它可以自己做到這一點(diǎn),但它需要一種創(chuàng)造驚喜的方法。 為此,它得到了一個(gè)驚喜工廠清單。 main方法如下所示:

public static void main(String[] args) {List<SurpriseFactory> surpriseFactories = Arrays.asList(new ChocolateFactory(),new QuoteFactory());Calendar calendar =Calendar.createWithSurprises(surpriseFactories);System.out.println(calendar.asText()); }

該項(xiàng)目的初始狀態(tài)絕不是拼圖之前最好的。 恰恰相反,這是一個(gè)簡單的起點(diǎn)。 它由一個(gè)包含所有必需類型的單個(gè)模塊(從抽象意義上講,不是Jigsaw解釋)組成:

  • “驚喜API” – Surprise和SurpriseFactory (均為接口)
  • “日歷API” – Calendar和CalendarSheet用于創(chuàng)建日歷
  • 驚喜–幾個(gè)Surprise和SurpriseFactory實(shí)現(xiàn)
  • Main –連接并運(yùn)行整個(gè)過程。

編譯和運(yùn)行非常簡單(Java 8的命令):

# compile javac -d classes/advent ${source files} # package jar -cfm jars/advent.jar ${manifest and compiled class files} # run java -jar jars/advent.jar

進(jìn)入拼圖土地

下一步雖小,但很重要。 它不會更改代碼或其組織,只會將其移至Jigsaw模塊中。

模組

那么什么是模塊? 引用強(qiáng)烈推薦的模塊系統(tǒng)狀態(tài) :

模塊是命名的,自描述的代碼和數(shù)據(jù)集合。 它的代碼被組織為一組包含類型(即Java類和接口)的軟件包。 其數(shù)據(jù)包括資源和其他種類的靜態(tài)信息。

為了控制其代碼如何引用其他模塊中的類型,模塊聲明要編譯和運(yùn)行它需要哪些其他模塊。 為了控制其他模塊中的代碼如何引用其包中的類型,模塊聲明了要導(dǎo)出的包中的哪個(gè)。

因此,與JAR相比,模塊具有JVM可以識別的名稱,聲明其依賴于其他模塊,并定義哪些包是其公共API的一部分。

名稱

模塊的名稱可以是任意的。 但是為了確保唯一性,建議堅(jiān)持使用包的反向URL命名模式。 因此,雖然這不是必需的,但通常意味著模塊名稱是它包含的軟件包的前綴。

依存關(guān)系

一個(gè)模塊列出了要編譯和運(yùn)行的其他模塊。 對于應(yīng)用程序和庫模塊而言,這都是正確的,但對于JDK本身中的模塊而言,這是正確的,它被分成了大約80個(gè)(請使用java -listmods )。

再次從設(shè)計(jì)概述中:

當(dāng)一個(gè)模塊直接依賴于模塊圖中的另一個(gè)模塊時(shí),第一個(gè)模塊中的代碼將能夠引用第二個(gè)模塊中的類型。 因此,我們說第一模塊讀取第二模塊,或者等效地,第二模塊可被第一模塊讀取 。

[…]

模塊系統(tǒng)確保每個(gè)依賴關(guān)系都由另一個(gè)模塊準(zhǔn)確地滿足,沒有兩個(gè)模塊互相讀取,每個(gè)模塊最多讀取一個(gè)定義給定程序包的模塊,并且定義同名程序包的模塊不會互相干擾。

當(dāng)違反任何一個(gè)屬性時(shí),模塊系統(tǒng)將拒絕編譯或啟動代碼。 這是對脆弱類路徑的巨大改進(jìn),在脆弱類路徑中,例如丟失的JAR僅在運(yùn)行時(shí)才發(fā)現(xiàn),從而使應(yīng)用程序崩潰。

還需要指出的是,只有模塊直接依賴于另一個(gè)模塊,才能訪問另一個(gè)模塊的類型。 因此,如果A依賴于B ,而B依賴于C ,那么除非明確要求A ,否則A將無法訪問C。

出口產(chǎn)品

一個(gè)模塊列出了它導(dǎo)出的軟件包。 這些包中的公共類型只能從模塊外部訪問。

這意味著public不再是真正的公眾。 非導(dǎo)出包中的公共類型與導(dǎo)出包中的非公共類型一樣,對外界隱藏。 它比當(dāng)今的私有包類型更加隱藏,因?yàn)槟K系統(tǒng)甚至不允許反射訪問它們。 由于拼圖是當(dāng)前實(shí)現(xiàn)的,命令行標(biāo)志是解決此問題的唯一方法。

實(shí)作

為了能夠創(chuàng)建模塊,項(xiàng)目需要在其根源目錄中包含module-info.java :

module advent {// no imports or exports }

等等,我不是說我們也必須聲明對JDK模塊的依賴嗎? 那么,為什么我們在這里沒有提到什么呢? 所有Java代碼都需要Object ,并且該類以及演示使用的其他少數(shù)幾個(gè)類也是模塊java.base一部分。 因此,實(shí)際上每個(gè) Java模塊都依賴于java.base ,這導(dǎo)致Jigsaw團(tuán)隊(duì)決定自動要求它。 因此,我們不必明確提及它。

最大的變化是要編譯和運(yùn)行的腳本(Java 9的命令):

# compile (include module-info.java) javac -d classes/advent ${source files} # package (add module-info.class and specify main class) jar -c \--file=mods/advent.jar \--main-class=advent.Main \${compiled class files} # run (specify a module path and simply name to module to run) java -mp mods -m advent

我們可以看到編譯幾乎相同–我們只需要在類列表中包括新的module-info.java 。

jar命令將創(chuàng)建所謂的模塊化JAR,即包含模塊的JAR。 與之前不同,我們不再需要任何清單,而是可以直接指定主類。 注意如何在目錄mods創(chuàng)建JAR。

完全不同的是啟動應(yīng)用程序的方式。 這樣做的目的是告訴Java在哪里可以找到應(yīng)用程序模塊(使用-mp mods ,這稱為模塊路徑 ),以及我們想啟動哪個(gè)模塊(使用-m advent )。

分成模塊

現(xiàn)在是時(shí)候真正了解Jigsaw并將其拆分為單獨(dú)的模塊了。

虛構(gòu)理由

“驚喜API”(即Surprise和SurpriseFactory取得了巨大的成功,我們希望將其與整體分離。

創(chuàng)造驚喜的工廠非?;钴S。 這里要做很多工作,它們經(jīng)常更改,并且使用的工廠因版本而異。 因此,我們想隔離它們。

同時(shí),我們計(jì)劃創(chuàng)建一個(gè)大型的圣誕節(jié)應(yīng)用程序,日歷僅是其中的一部分。 因此,我們也希望為此提供一個(gè)單獨(dú)的模塊。

我們最終得到以下模塊:

  • 驚喜 – Surprise and SurpriseFactory
  • 日歷 –日歷,使用Surprise API
  • 工廠 – SurpriseFactory實(shí)現(xiàn)
  • main –原來的應(yīng)用程序,現(xiàn)在已經(jīng)鏤空到Main類

通過查看它們之間的依賴關(guān)系,我們可以發(fā)現(xiàn)驚喜并不取決于其他模塊。 日歷和工廠都使用它的類型,因此必須依賴它。 最后, main使用工廠來創(chuàng)建日歷,因此它依賴于兩者。

實(shí)作

第一步是重新組織源代碼。 我們將遵循官方快速入門指南建議的目錄結(jié)構(gòu),并將所有模塊放在src的自己的文件夾中:

src- advent.calendar: the "calendar" module- org ...module-info.java- advent.factories: the "factories" module- org ...module-info.java- advent.surprise: the "surprise" module- org ...module-info.java- advent: the "main" module- org ...module-info.java .gitignore compileAndRun.sh LICENSE README

為了保持可讀性,我刪節(jié)了org下面的文件夾。 缺少的是軟件包以及每個(gè)模塊的最終源文件。 完整地在GitHub上查看。

現(xiàn)在,讓我們看看這些模塊信息必須包含什么以及如何編譯和運(yùn)行應(yīng)用程序。

沒有必要的條款,因?yàn)镾urprise沒有依賴性。 (除了java.base ,它始終是隱式必需的。)它導(dǎo)出包advent.surprise因?yàn)樗瑑蓚€(gè)類Surprise和SurpriseFactory 。

因此module-info.java如下所示:

module advent.surprise {// requires no other modules// publicly accessible packagesexports advent.surprise; }

編譯和打包與上一節(jié)非常相似。 實(shí)際上,這甚至更容易,因?yàn)橐馔馐录话魏沃饕悇e:

# compile javac -d classes/advent.surprise ${source files} # package jar -c --file=mods/advent.surprise.jar ${compiled class files}

日歷使用來自Surprise API的類型,因此模塊必須依賴Surprise 。 向模塊添加requires advent.surprise即可實(shí)現(xiàn)。

該模塊的API由Calendar類組成。 為了使其可公開訪問,必須導(dǎo)出包含軟件包advent.calendar 。 請注意,同一包私有的CalendarSheet在模塊外部將不可見。

但有一個(gè)附加的扭曲:我們剛剛作出Calendar.createWithSurprises( List<SurpriseFactory> )公布,從驚喜模塊暴露類型。 因此,除非讀取日歷的模塊也需要驚訝 ,否則Jigsaw將阻止它們訪問這些類型,這將導(dǎo)致編譯和運(yùn)行時(shí)錯(cuò)誤。

將require子句標(biāo)記為public可解決此問題。 有了它,任何依賴日歷的模塊也會讓人吃驚 。 這稱為隱式可讀性 。

最終的模塊信息如下所示:

module advent.calendar {// required modulesrequires public advent.surprise;// publicly accessible packagesexports advent.calendar; }

編譯幾乎像以前一樣,但是當(dāng)然必須在此反映對驚奇的依賴。 為此,將編譯器指向目錄mods就足夠了,因?yàn)樗璧哪K:

# compile (point to folder with required modules) javac -mp mods \-d classes/advent.calendar \${source files} # package jar -c \--file=mods/advent.calendar.jar \${compiled class files}

該工廠實(shí)現(xiàn)SurpriseFactory所以這個(gè)模塊必須依靠驚喜 。 并且由于它們從已發(fā)布的方法返回Surprise實(shí)例,因此與上述相同的思路導(dǎo)致了requires public子句的出現(xiàn)。

可以在包advent.factories找到工廠,因此必須將其導(dǎo)出。 請注意,在另一個(gè)模塊中找到的公共類AbstractSurpriseFactory在此模塊外部無法訪問。

這樣我們得到:

module advent.factories {// required modulesrequires public advent.surprise;// publicly accessible packagesexports advent.factories; }

編譯和打包類似于日歷 。

我們的應(yīng)用程序需要日歷和工廠這兩個(gè)模塊進(jìn)行編譯和運(yùn)行。 它沒有要導(dǎo)出的API。

module advent {// required modulesrequires advent.calendar;requires advent.factories;// no exports }

編譯和打包與上一節(jié)的單個(gè)模塊相似,不同之處在于編譯器需要知道在哪里尋找所需的模塊:

#compile javac -mp mods \-d classes/advent \${source files} # package jar -c \--file=mods/advent.jar \--main-class=advent.Main \${compiled class files} # run java -mp mods -m advent

服務(wù)

拼圖通過實(shí)現(xiàn)服務(wù)定位器模式實(shí)現(xiàn)松散耦合,在該模式中 ,模塊系統(tǒng)本身充當(dāng)定位器。 讓我們看看情況如何 。

虛構(gòu)理由

最近有人讀了一篇關(guān)于冷松耦合的博客文章。 然后她從上面看我們的代碼,抱怨主機(jī)和工廠之間的緊密關(guān)系。 主為什么還要知道工廠 ?

因?yàn)椤?

public static void main(String[] args) {List<SurpriseFactory> surpriseFactories = Arrays.asList(new ChocolateFactory(),new QuoteFactory());Calendar calendar =Calendar.createWithSurprises(surpriseFactories);System.out.println(calendar.asText()); }

真? 只是為了實(shí)例化完美抽象的某些實(shí)現(xiàn)( SurpriseFactory )?

而且我們知道她是對的。 讓其他人為我們提供實(shí)現(xiàn)將消除直接依賴。 更好的是,如果說中間人能夠在模塊路徑上找到所有實(shí)現(xiàn),則可以通過在啟動之前添加或刪除模塊來輕松配置日歷的驚喜。

拼圖確實(shí)可以做到這一點(diǎn)。 我們可以有一個(gè)模塊來指定它提供接口的實(shí)現(xiàn)。 另一個(gè)模塊可以表示它使用所述接口,并使用ServiceLocator查找所有實(shí)現(xiàn)。

我們利用這個(gè)機(jī)會將工廠分割成巧克力,然后報(bào)價(jià)并最終得到以下模塊和依賴項(xiàng):

  • 驚喜 – Surprise and SurpriseFactory
  • 日歷 –日歷,使用Surprise API
  • 巧克力 – ChocolateFactory即服務(wù)
  • quote – QuoteFactory即服務(wù)
  • 主要 –應(yīng)用程序; 不再需要單個(gè)工廠

實(shí)作

第一步是重新組織源代碼。 之前的唯一變化是src/advent.factories被src/advent.factory.chocolate和src/advent.factory.quote 。

讓我們看一下各個(gè)模塊。

兩者都沒有改變。

除某些名稱外,兩個(gè)模塊都是相同的。 讓我們看一下巧克力,因?yàn)樗牢丁?

和工廠以前一樣,該模塊requires public 驚喜模塊。

更有趣的是其出口。 它提供了SurpriseFactory的實(shí)現(xiàn),即ChocolateFactory ,其指定如下:

provides advent.surprise.SurpriseFactorywith advent.factory.chocolate.ChocolateFactory;

由于此類是其公共API的全部,因此不需要導(dǎo)出其他任何內(nèi)容。 因此,沒有其他出口條款是必要的。

我們最終得到:

module advent.factory.chocolate {// list the required modulesrequires public advent.surprise;// specify which class provides which serviceprovides advent.surprise.SurpriseFactorywith advent.factory.chocolate.ChocolateFactory; }

編譯和打包很簡單:

javac -mp mods \-d classes/advent.factory.chocolate \${source files} jar -c \--file mods/advent.factory.chocolate.jar \${compiled class files}

關(guān)于main的最有趣的部分是它如何使用ServiceLocator查找SurpriseFactory的實(shí)現(xiàn)。 從其主要方法 :

List surpriseFactories = new ArrayList<>(); ServiceLoader.load(SurpriseFactory.class).forEach(surpriseFactories::add);

我們的應(yīng)用程序現(xiàn)在僅需要日歷,但必須指定它使用SurpriseFactory 。 它沒有要導(dǎo)出的API。

module advent {// list the required modulesrequires advent.calendar;// list the used servicesuses advent.surprise.SurpriseFactory;// exports no functionality }

編譯和執(zhí)行與以前一樣。

我們確實(shí)可以通過簡單地從模塊路徑中刪除工廠模塊之一來更改日歷最終將包含的驚喜。 整齊!

摘要

就是這樣了。 我們已經(jīng)看到了如何將單片應(yīng)用程序移動到單個(gè)模塊中以及如何將其拆分為多個(gè)模塊。 我們甚至使用服務(wù)定位器將我們的應(yīng)用程序與服務(wù)的具體實(shí)現(xiàn)分離開來。 所有這些都在GitHub上,因此請查看更多代碼!

但是還有更多要討論的! 拼圖帶來了一些不兼容問題,但也解決了許多不兼容問題。 而且我們還沒有討論反射如何與模塊系統(tǒng)交互以及如何遷移外部依賴項(xiàng)。

如果您對這些主題感興趣,請?jiān)谖业牟┛蜕嫌^看Jigsaw標(biāo)簽 ,因?yàn)樵诮酉聛淼膸讉€(gè)月中我一定會寫關(guān)于它們的。

翻譯自: https://www.javacodegeeks.com/2015/12/project-jigsaw-hands-guide.html

總結(jié)

以上是生活随笔為你收集整理的拼图项目动手指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。