版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、追求代碼質(zhì)量(11):用aop進(jìn)行防御性編程-編程開發(fā)技術(shù)追求代碼質(zhì)量(11):用aop進(jìn)行防御 性編程原文出處:ibm中國(guó)開發(fā)人員測(cè)試的主要缺點(diǎn)是:絕大部分測(cè)試都是在理想的場(chǎng)景屮進(jìn)行的。在這些 情況下并不會(huì)出現(xiàn)缺陷一一能導(dǎo)致出現(xiàn)問題的往往是那些邊界情況。什么是邊界情況呢?比方說,把?null?值傳入一個(gè)并未編寫如何處理?null?值的 方法中,這就是一種邊界情況。大多數(shù)開發(fā)人員通常都不能成功測(cè)試這樣的場(chǎng)景, 因?yàn)檫@沒多大意義。但不管有沒有意義,發(fā)生了這樣的情況,就會(huì)拋出一 個(gè)?nullpointerexception,然后整個(gè)程序就會(huì)崩潰。本刀,我將為您推薦一種多層面的方法,來處理代碼中那些
2、不易預(yù)料的缺陷。嘗 試為應(yīng)用程序整合進(jìn)防御性編程、契約式設(shè)計(jì)和-種叫做oval的易用的通用驗(yàn) 證框架。將敵人暴露出來清單1中的代碼為給定的?class?對(duì)象(省去了?java. lang. object,因?yàn)樗?對(duì)象都最終由它擴(kuò)展)構(gòu)建一個(gè)類層次。但如果仔細(xì)看的話,您會(huì)注意到一個(gè)有 待發(fā)現(xiàn)的潛在缺陷,即該方法對(duì)對(duì)象值所做的假設(shè)。清單1.不檢驗(yàn)null的方法public static hierarchy buildhierarchy(class clzz) hierarchy hi er 二 new hierarchyo ;hier. setbaseclass(clzz);class supe
3、rclass 二 clzz. gctsuperclass ();if (superclass != null && superclass. getname(). equals(/zjava. lang. object") return hier;elsewhile(clzz. getsuperclass() != null) &&(!clzz. getsuperclass (). getname(). equals (/zjava. lang. object") clzz 二 clzz.getsuperclass();hier.addclas
4、s(clzz);return hier;剛編好這個(gè)方法,我還沒注意到這個(gè)缺陷,但由于我狂熱地崇拜開發(fā)人員測(cè)試, 于是我編寫了一個(gè)使用testng的常規(guī)測(cè)試。而且,我述利用了 testng方便 的?dataprovider?特性,借助該特性,我創(chuàng)建了一個(gè)通用的測(cè)試用例并通過另一 個(gè)方法來改變它的參數(shù)。運(yùn)行清單2中定義的測(cè)試用例會(huì)產(chǎn)生兩個(gè)通過結(jié)果! 一切都運(yùn)轉(zhuǎn)良好,不是嗎?清單2.驗(yàn)證兩個(gè)值的testng測(cè)試import java, util .vector;import static org.testng. assert. asscrtequals;import org. testng. ann
5、otations. dataprovider;import org.testng. annotations. test;public class bui 1dhierarchytest dataprovider (name = "class-hierarchies") public object datavalues ()return new objectvector, class, new string /zjava. util. abstractlisz/java, ut訂.abstractcollcctioiwstring, class, new string ;tc
6、st(dataprovidcr 二"class-hierarchies")public void verifyhierarchies(class clzz, string names) throws exception!hierarchy hier 二 hierarchybuilder. buildhierarchy (clzz);assertequal s (hier. gethierarchycleissnennes (), names, "values were not equal");至此,我還是沒有發(fā)現(xiàn)缺陷,但一些代碼問題卻困擾著我。如果有人不
7、經(jīng)意地 為?class?參數(shù)傳入一個(gè)?null?值會(huì)怎么樣呢?清單1?中第4行的 clzz. gctsuperclass ()?調(diào)用會(huì)拋出一個(gè)?nullpointcrexccption,是這樣嗎?測(cè)試我的理論很容易;其至都不用從頭開始。僅僅把?null, null?添加到初 始?bu i 1 dh i er ar chyt e s t ?的?datavalues?方法中的多維?object?數(shù)組中,然后再 次運(yùn)行它。我定會(huì)得到如圖1所示的?nullpointerexception:gyrate4 止圖 l 可怕的 nulipointerexceptionag逢 m zsfated testse
8、 a adm(iwo)0. venfytterttdtes3 sw/)ttarmdm(i=e excapoan多1 "ajaromsair<)er£jxf(tt)n上s gnv<»*ard4d«na>tw<hr.g為6umor.ujdcv.6ygvchy錢三 .hcnvet<m4m*.6y抵 krf>tterar<memprorfcir:"me:?m三 « aveaect 曲六hetha如ewcrk<"r&me h«rg三 mrmeaeclmrvefmhodc
9、om<ru<rf.rrzaojrar«>r<i sebree)三 m dr、o4»p<rh2k<*wrlt<i rt2m(urtoon ry)=««r*d 切 fettect me<n)d rwotefthaomr» source)s «t arg心rttngclarndjmhew>1«|p<r.r¥v*ethod(gf<miie|pw .”.953)三 .qrgzftg.femm.lry心 exibzgexmr.eysn)二& cnerf?
10、)參見這里的?全圖。防御性編程一旦岀現(xiàn)這個(gè)問題,下一步就是要拿出對(duì)抗的策略。問題是我控制不了這個(gè)方法 能否接收這種輸入。對(duì)于這類問題,開發(fā)人員通常會(huì)使用防御性編程技術(shù),該技 術(shù)專門用來在發(fā)生摧毀性后果前捕捉潛在錯(cuò)誤。對(duì)象驗(yàn)證是處理不確定性的一項(xiàng)經(jīng)典的防御性編程策略。相應(yīng)地,我會(huì)添加一項(xiàng) 檢驗(yàn)來驗(yàn)證clzz?是否為?null,如清單3所示。如杲其值最終為?null,我就 會(huì)拋出一個(gè)runtimeexception?來警告他人注意這個(gè)潛在問題。清單3.添加驗(yàn)證null值的檢驗(yàn)publ ic static hierarchy buildhierarchy(class clzz) if (clzz =
11、 null)throw new runtimeexception(zzclass parameter can not be null");hierarchy hier 二 new hierarchy();hier.setbascclass(clzz);class superclass 二 clzz.getsuperclass ();if(superclass != null &&superclass. gctnamc () equals (z/java. lang. objcct)return hier;else while(clzz. getsuperclass()
12、 != nul1) &&(!clzz. getsuperclass(). getname(). equals(z,java. lang. object") clzz = clzz. getsuperclass();hier.addclass(clzz);return hier;很自然,我也會(huì)編寫一個(gè)快速測(cè)試用例來鏗證我的檢驗(yàn)是否真能避 免?nu 11 pointerexception,如清單 4 所示:清單4.驗(yàn)證null檢驗(yàn)test(expectedexceptions=runtimeexception. class) public void verifyhiera
13、rch)null () throws exception!class clzz 二 null;hierarchybui1der. bui1dhierarchy(null);在本例屮,防御性編程似乎解決了問題。但僅依靠這項(xiàng)策略會(huì)存在一些缺陷。防御的缺陷盡管防御性編程冇效地保證了方法的輸入條件,但如果在一系列方法中使用它, 不免過于重復(fù)。熟悉面向方面編程(或aop)的人們會(huì)把它認(rèn)為是橫切關(guān)注點(diǎn), 這意味著防御性編程技術(shù)橫跨了代碼庫(kù)。許多不同的對(duì)彖都釆用這些語(yǔ)法,盡管 從純面向?qū)ο蟮挠^點(diǎn)來看這些語(yǔ)法跟對(duì)象毫不相關(guān)。而且,橫切關(guān)注點(diǎn)開始滲入到契約式設(shè)計(jì)5憂)的概念中。dbc是這樣一項(xiàng)技 術(shù),它通過在組
14、件的接口顯式地陳述每個(gè)組件應(yīng)有的功能和客戶機(jī)的期望值來確 保系統(tǒng)屮所有的組件完成它們應(yīng)盡的職責(zé)。從dbc的角度講,組件應(yīng)有的功能 被認(rèn)為是后置條作,本質(zhì)上就是組件的責(zé)任,而客戶機(jī)的期槊值則普遍被認(rèn)為是 前置條件。另外,在純dbc術(shù)語(yǔ)中,遵循dbc規(guī)則的類針對(duì)其將維護(hù)的內(nèi)部一 致性與外部世界有一個(gè)契約,即人所共知的類/變式。契約式設(shè)計(jì)我在以前的一篇關(guān)于用nice編程的文章屮介紹過dbc的概念,nice是一門與 jre兼容的面向?qū)﹀杈幊陶Z(yǔ)言,它的特點(diǎn)是側(cè)重于模塊性、可表達(dá)性和安全性。 有趣的是,nice并入了功能性開發(fā)技術(shù),其屮包括了一些在面向方面編程屮的 技術(shù)。功能性開發(fā)使得為方法指定前置條件和
15、后置條件成為可能。盡管nice支持dbc,但它與java?語(yǔ)言完全不同,因而很難將其用于開發(fā)。 幸運(yùn)的是,很多針對(duì)java語(yǔ)言的庫(kù)也都為dbc提供了方便。每個(gè)庫(kù)都有其優(yōu) 點(diǎn)和缺點(diǎn),每個(gè)庫(kù)在dbc內(nèi)針對(duì)java語(yǔ)言進(jìn)行構(gòu)建的方法也不同;但最近的 一些新特性大都利用了 aop來更多地將dbc關(guān)注點(diǎn)包括進(jìn)來,這些關(guān)注點(diǎn)基本 上就相當(dāng)于方法的包裝器。前置條件在包裝過的方法執(zhí)行前擊發(fā),后置條件在該方法完成后擊發(fā)。使用aop 構(gòu)建dbc結(jié)構(gòu)的一個(gè)好處(請(qǐng)不要同該語(yǔ)言本身相混淆?。┦?可以在不需要dbc 關(guān)注點(diǎn)的環(huán)境屮將這些結(jié)構(gòu)關(guān)掉(就像斷言能被關(guān)掉一樣)。以橫切的方式對(duì)待 安全性關(guān)注點(diǎn)的真正妙處是:可以有
16、效地產(chǎn)勸?這些關(guān)注點(diǎn)。眾所周知,重用是 面向?qū)ο缶幊痰囊粋€(gè)基本原則。aop如此完美地補(bǔ)充了 oop難道不是一件極好 的事情嗎?結(jié)合了 oval的aopoval是一個(gè)通用的驗(yàn)證框架,它通過aop支持簡(jiǎn)單的dbc結(jié)構(gòu)并明確地允許:為類字段和方法返冋值指定約束條件為結(jié)構(gòu)參數(shù)指定約束條件為方法參數(shù)指定約束條件此外,oval還帶來大量預(yù)定義的約束條件,這讓創(chuàng)建新條件變得和當(dāng)容易。由于oval使用aspectj的aop實(shí)現(xiàn)來為dbc概念定義建戎,所以必須將 aspectj并入一個(gè)使用oval的項(xiàng)廿中。對(duì)于不熟悉aop和aspectj的人們來 說,好消息是這不難實(shí)現(xiàn),且使用oval (甚至是創(chuàng)建新的約束條件
17、)并不需要 真正對(duì)方而進(jìn)行編碼,只需編寫一個(gè)簡(jiǎn)單的自引導(dǎo)程序即可,該程序會(huì)使oval 所附帶的默認(rèn)方面植入您的代碼中。在創(chuàng)建這個(gè)自引導(dǎo)程序方面前,要先下載aspectjo具體地說,您需要將?aspect jtool s?和?aspect jrt?jar文件并入您的構(gòu)建中來編譯所需的自引導(dǎo) 程序方面并將其編入您的代碼中。自引導(dǎo)aop下載了 aspectj后,下一步是創(chuàng)建一個(gè)可擴(kuò)展oval?guardaspect?的方面。它 本身不需要做什么,如清單5所示。請(qǐng)確保文件的擴(kuò)展名以亦結(jié)束,但不要 試著用常規(guī)的?javac?對(duì)其進(jìn)行編譯。清單5. defaultguardaspect自引導(dǎo)程序方面imp
18、ort net. sf. oval, aspectj. guardaspect;public aspect defaultguardaspect extends guardaspectpublic defaultguardaspect()super ();aspectj引入了一個(gè)ant任務(wù),稱為?iajc,充當(dāng)著?javac?的角色;此過程對(duì) 方面進(jìn)行編譯并將其編入主體代碼中。在本例中,只要是我指定了 oval約束條 件的地方,在oval代碼屮定義的邏輯就會(huì)編入我的代碼,進(jìn)而充當(dāng)起前置條件 和后置條件。請(qǐng)記住?iajc?代替t?javaco例如,清單6是我的ant build. xml文件的一
19、個(gè) 代碼片段,其屮對(duì)代碼進(jìn)行了編譯并把通過代碼標(biāo)注發(fā)現(xiàn)的所右oval方面編入 進(jìn)來,如下所示:清單6.用aop編譯的ant構(gòu)建文件片段<target name二aspectjc depends二get-deps><taskdcfresource二org/aspectj/tools/ant/taskdefs/aspectjtaskdefs properties" <classpath><path refid二bu訂d. classpath" />/classpath</taskdcf><iajc destdir=/z
20、$ classesdir/z debu薩on" source二 1. 5"><classpath><path refid二buiid. classpath" /></classpath><sourceroots><pathelement location二src/java" /><pathelement location二test/java /></sourceroots></iajc></target>為oval鋪好了路、為aop過程做了引
21、導(dǎo)之后,就可以開始使用java 5標(biāo)注 來為代碼指定簡(jiǎn)單的約束條件了。oval的可重用約束條件用oval為方法指定前置條件必須對(duì)方法參數(shù)進(jìn)行標(biāo)注。相應(yīng)地,當(dāng)調(diào)用一個(gè)用 oval約束條件標(biāo)注過的方法吋,oval會(huì)在該方法真正執(zhí)行麗驗(yàn)證該約朿條件。在我的例子中,我想要指定當(dāng)?class?參數(shù)的值為?null?時(shí),buildllierarchy? 方法不能被調(diào)用。oval通過?notnull?標(biāo)注支持此約束條件,該標(biāo)注在方法所 需的所有參數(shù)前指定。也要注意,任何想要使用oval約束條件的類也必須在類 層次上指定?guarded?標(biāo)注,就像我在清單7中所做的那樣:清單7. oval約束條件import
22、 net.sf. oval, annotations. guarded;import net. sf. oval, constraints. notnull;guardedpublic class hierarchybuiider public static hierarchy bui1dhierarchy(notnull class clzz) hierarchy hier 二 new hierarchy();hicr.sctbaseclass(clzz);class superclass 二 clzz.getsuperclass();if(superclass != null &&
23、amp;superclass. gctnamc () equals (z/java. lang. objcct) return hier;else while(clzz. getsuperclass() != null) &&(!clzz. getsuperclass(). getname(). equals(z,java. lang. object") clzz = clzz. getsuperclass (); hier. addclass (clzz);return hier;通過標(biāo)注指定這個(gè)約朿條件意味著我的代碼不再會(huì)被重復(fù)的條件弄得亂七八耕, 這些條件檢查?
24、null?值,并且一旦找到該值就會(huì)拋出異?!,F(xiàn)在這項(xiàng)邏輯由oval 處理,且處理的方法有些相似 事實(shí)上,如果違反了約束條件,oval會(huì)拋 出一個(gè)?constraintsviolatcdexccption,它是?runtimcexccption?的 了類。當(dāng)然,我卜一步就要編譯?hierarchybuilder?類和?清單5?屮相應(yīng)的?defaultguardaspect?類。我用?清單6?中的?iajc?任務(wù)來實(shí)現(xiàn)這一目的,這 樣我就能把oval的行為編入我的代碼屮了。接下來,我更新?清單4?中的測(cè)試用例來驗(yàn)證是否處出了一個(gè)?constraintsviolatcdexccption,如清單 8
25、 所示:清單 & 驗(yàn)證是否拋出 了 constraintsviolatedexception©test(expectedexceptions二constraintsviolatedexception.class) public void verifyhierarchynull() throws exceptionclass clzz = null;hierarchybuilder. bui1dhierarchy (clzz);指定后置條件止如您所見,指定而置條件其實(shí)相當(dāng)容易,指定后置條件的過程也是一樣。例如, 如果我想對(duì)所冇調(diào)用?buildhierarchy?的程序保證它不會(huì)
26、返回?null?值(這樣, 這些調(diào)用程序就不需要再檢查這個(gè)了),我可以在方法聲明之上放置一 個(gè)?notnull?標(biāo)注,如清單9所示:清單9. oval中的后置條件©notnullpublic static hierarchy buildhierarchy(notnul1 class clzz) /method body當(dāng)然,notnull?絕不是oval提供的惟一約束條件,但我發(fā)現(xiàn)它能非常有效地 限制這些令人討厭的?nullpointcrexccption,或至少能夠快速地暴謬?它們。更多的oval約束條件oval也支持在方法調(diào)用前或后對(duì)類成員進(jìn)行預(yù)先驗(yàn)證。這種機(jī)制具有限制針對(duì) 特定
27、約束條件的重復(fù)條件測(cè)試的好處,如集合大小或之前討論過的非?null?的情 況。例如,在清單10屮,我使用?hierarchybu訂der?定義了一個(gè)為類層次構(gòu)建報(bào)告 的ant任務(wù)。請(qǐng)注意?execute()?方法是如何調(diào)用?validate的,后者會(huì)依次驗(yàn) 證?fileset?類成員是否含值;如果不含,會(huì)拋出一個(gè)異常,因?yàn)闆]有了要評(píng)估 的類,該報(bào)告不能運(yùn)行。清單10.帶條件檢驗(yàn)的hierarchybuiidertaskpublic class hierarch)buiidertask extends task private report report;private list fileset
28、;private void validate() throws buildexceptionif (! (this. fileset. size() > 0) throw new buildexception(/zmust supply classes to evaluate");if (this, report = nul 1)this. log(z,no report defined, printing xml to system, out);public void execute() throws buildexccption validate ();string cla
29、sses = this. getqualifiedclassnames(this. fileset); hierarchy hclz 二 new hierarchyclasses, length;try for(int x = 0; x < classes, length; x+) hclzx = hierarch)builder. buildhierarchy (classesx);batchhi erarchyxmlreport xml er = new batchhi erarchyxmlreport(new date(), hclz);this.handlereportcreat
30、ion(xmler);catch (classnotfoundexception e) throw new buiidexception(zzunable to load class check classpath! + e. £etmessage ();/more methods below.因?yàn)槲矣玫氖莖val,所以我可以完成下列任務(wù):對(duì)?fileset?類成員指定一個(gè)約束條件,確保使用?size?標(biāo)注時(shí)其大小總是至少 為1或更大。 確保在使用?prevalidatethis?標(biāo)注調(diào)用?execute ()?方法湖驗(yàn)證這個(gè)約束條 件。這兩步讓我能夠有效地去除?validate()
31、?方法屮的條件檢驗(yàn),讓oval為我完成 這些,如清單11所示:清單11.經(jīng)過改進(jìn)、無(wú)條件檢驗(yàn)的hierarchybuiidertask©guardedpublic class hierarchybuiidertask extends task private report report;sizc(min = 1)private list fileset;private void validate() throws buildexception if (this. report 二二 nul1) this.1og("no report defined, printing xm
32、l to system.out");©prevaiidatethi spublic void execute() throws buildexception validate();string classes 二 this. getqualifiedclassnames (this.fileset);hierarchy hclz 二 new hierarchyclasses, length;try for(int x = 0; x < classes.length; x+)hclzx二 hierarchybuilder. buildhierarchy(classesx
33、);batchllicrarchyxmlrcport xmlcr = new batchllicrarchyxmlrcport (newdate(), hclz);this.hand1ereportcreation(xmler);catch(classnotfoundexception e) throw new buildexception(unable to load class check classpath! + c. gctmcssagco);/more methods below.清單11中的?execute()?一經(jīng)調(diào)用(由ant完成),oval就會(huì)驗(yàn)證?f訂eset? 成員。如果
34、其為空,就意味著沒有指定任何要評(píng)估的類,就會(huì)拋岀一個(gè)?constraintsviolatedexceptiono這個(gè)界常會(huì)暫停這一過程,就像初始代碼 一樣,只不過初始代碼會(huì)拋出一個(gè)?bui 1 dexception0彳口口防御性編程結(jié)構(gòu)阻止了一個(gè)又一個(gè)缺陷,但這些結(jié)構(gòu)本身卻不免為代碼添加了重 復(fù)的邏輯。把防御性編程技術(shù)和而向方而編程(通過契約式設(shè)計(jì))聯(lián)系起來是抵 御所有重復(fù)性代碼的一道堅(jiān)強(qiáng)防線。oval并不是惟一可用的dbc庫(kù),事實(shí)上其dbc結(jié)構(gòu)對(duì)比其他框架來說是相當(dāng) 有限的(例如,它未提供指定類不變式的簡(jiǎn)易方法)。從另一方面講,oval很 容易使用,對(duì)約束條件也有很大的選擇余地,若想要花少量力氣就可向代碼添加 驗(yàn)證約束條件,它無(wú)疑是個(gè)上佳之選。另外,用oval創(chuàng)建定制約束條件也相當(dāng) 簡(jiǎn)單,所以請(qǐng)不要再添加條件檢驗(yàn)了,盡情享用aop吧!參考資料學(xué)習(xí) 您nj以參閱木文在developerworks全球站點(diǎn)上的?英文原文?。 “aop 解決緊密耦合的難題” (andrew glover, developerworks, 2004 年 2 月): 親自體驗(yàn)一下aop的功能設(shè)計(jì)概念z (靜態(tài)橫切)如何把可能亂成一團(tuán)的緊密 耦合的
溫馨提示
- 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)院業(yè)務(wù)副院長(zhǎng)職責(zé)(五篇)
- 網(wǎng)絡(luò)課程設(shè)計(jì)的分類
- 網(wǎng)頁(yè)課程設(shè)計(jì)摘要模板
- 網(wǎng)上書店c 課程設(shè)計(jì)
- 微機(jī)原理通訊錄課程設(shè)計(jì)
- 聯(lián)想記憶課程設(shè)計(jì)
- 電話禮儀課程設(shè)計(jì)
- 職工系統(tǒng)Delphi課程設(shè)計(jì)
- 家政保潔公司營(yíng)業(yè)員服務(wù)總結(jié)
- 美的物流課程設(shè)計(jì)
- 公務(wù)員行測(cè)真題題庫(kù)及答案
- 2025支部會(huì)議記錄范文
- 部隊(duì)保密安全課件
- 園林施工技術(shù)創(chuàng)新-洞察分析
- 醫(yī)院窗簾、隔簾采購(gòu) 投標(biāo)方案(技術(shù)方案)
- 2025屆湖北省高三上學(xué)期12月聯(lián)考語(yǔ)文試題
- 國(guó)家開放大學(xué)《Photoshop圖像處理》章節(jié)測(cè)試題參考答案
- 期末檢測(cè)卷(試題)-2024-2025學(xué)年三年級(jí)上冊(cè)數(shù)學(xué)人教版
- 江蘇省南京市2023-2024學(xué)年高一上學(xué)期物理期末試卷(含答案)
- 新疆烏魯木齊市(2024年-2025年小學(xué)五年級(jí)語(yǔ)文)人教版階段練習(xí)(上學(xué)期)試卷及答案
- 2024年人教版八年級(jí)生物上冊(cè)期末考試卷(附答案)
評(píng)論
0/150
提交評(píng)論