版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、面向接口編程1.面向接口編程和面向?qū)ο缶幊淌鞘裁搓P(guān)系首先,面向接口編程和面向?qū)ο缶幊滩⒉皇瞧郊壍?,它并不是比面向?qū)ο缶幊谈冗M的一種獨立的編程思想,而是附屬于面向?qū)ο笏枷塍w系,屬于其一部分。或者說,它是面向?qū)ο缶幊腆w系中的思想精髓之一。2.接口的本質(zhì)接口,在表面上是由幾個沒有主體代碼的方法定義組成的集合體,有唯一的名稱,可以被類或其他接口所實現(xiàn)(或者也可以說繼承)。它在形式上可能是如下的樣子:interface InterfaceName void Method1(); void
2、160;Method2(int para1); void Method3(string para2,string para3); 那么,接口的本質(zhì)是什么呢?或者說接口存在的意義是什么。我認為可以從以下兩個視角考慮:1)接口是一組規(guī)則的集合,它規(guī)定了實現(xiàn)本接口的類或接口必須擁有的一組規(guī)則。體現(xiàn)了自然界“如果你是則必須能”的理念。例如,在自然界中,人都能吃飯,即“如果你是人,則必須能吃飯”。那么模擬到計算機程序中,就應(yīng)該有一個IPerson(習慣上,接口名由“I”開頭)接口,并有一個方法叫Eat(),然
3、后我們規(guī)定,每一個表示“人”的類,必須實現(xiàn)IPerson接口,這就模擬了自然界“如果你是人,則必須能吃飯”這條規(guī)則。從這里,我想各位也能看到些許面向?qū)ο笏枷氲臇|西。面向?qū)ο笏枷氲暮诵闹?,就是模擬真實世界,把真實世界中的事物抽象成類,整個程序靠各個類的實例互相通信、互相協(xié)作完成系統(tǒng)功能,這非常符合真實世界的運行狀況,也是面向?qū)ο笏枷氲木琛?)接口是在一定粒度視圖上同類事物的抽象表示。注意這里我強調(diào)了在一定粒度視圖上,因為“同類事物”這個概念是相對的,它因為粒度視圖不同而不同。例如,在我的眼里,我是一個人,和一頭豬有本質(zhì)區(qū)別,我可以接受我和我同學是同類這個說法,但絕不能接受我和一頭豬是同類。但
4、是,如果在一個動物學家眼里,我和豬應(yīng)該是同類,因為我們都是動物,他可以認為“人”和“豬”都實現(xiàn)了IAnimal這個接口,而他在研究動物行為時,不會把我和豬分開對待,而會從“動物”這個較大的粒度上研究,但他會認為我和一棵樹有本質(zhì)區(qū)別。現(xiàn)在換了一個遺傳學家,情況又不同了,因為生物都能遺傳,所以在他眼里,我不僅和豬沒區(qū)別,和一只蚊子、一個細菌、一顆樹、一個蘑菇乃至一個SARS病毒都沒什么區(qū)別,因為他會認為我們都實現(xiàn)了IDescendable這個接口(注:descend vi. 遺傳),即我們都是可遺傳的東西,他不會分別研究我們,而會將所有生物作為同類進行研究,在他眼里沒有人和病毒之分,只有
5、可遺傳的物質(zhì)和不可遺傳的物質(zhì)。但至少,我和一塊石頭還是有區(qū)別的??刹恍业氖虑榘l(fā)生了,某日,地球上出現(xiàn)了一位偉大的人,他叫列寧,他在熟讀馬克思、恩格斯的辯證唯物主義思想巨著后,頗有心得,于是他下了一個著名的定義:所謂物質(zhì),就是能被意識所反映的客觀實在。至此,我和一塊石頭、一絲空氣、一條成語和傳輸手機信號的電磁場已經(jīng)沒什么區(qū)別了,因為在列寧的眼里,我們都是可以被意識所反映的客觀實在。如果列寧是一名程序員,他會這么說:所謂物質(zhì),就是所有同時實現(xiàn)了“IReflectabe”和“IEsse”兩個接口的類所生成的實例。(注:reflect v. 反映 esse n. 客觀實在)也許你會覺得我上
6、面的例子像在瞎掰,但是,這正是接口得以存在的意義。面向?qū)ο笏枷牒秃诵闹唤凶龆鄳B(tài)性,什么叫多態(tài)性?說白了就是在某個粒度視圖層面上對同類事物不加區(qū)別的對待而統(tǒng)一處理。而之所以敢這樣做,就是因為有接口的存在。像那個遺傳學家,他明白所有生物都實現(xiàn)了IDescendable接口,那只要是生物,一定有Descend()這個方法,于是他就可以統(tǒng)一研究,而不至于分別研究每一種生物而最終累死??赡苓@里還不能給你一個關(guān)于接口本質(zhì)和作用的直觀印象。那么在后文的例子和對幾個設(shè)計模式的解析中,你將會更直觀體驗到接口的內(nèi)涵。3.面向接口編程綜述通過上文,我想大家對接口和接口的思想內(nèi)涵有了一個了解,那么什么是面向接口編程
7、呢?我個人的定義是:在系統(tǒng)分析和架構(gòu)中,分清層次和依賴關(guān)系,每個層次不是直接向其上層提供服務(wù)(即不是直接實例化在上層中),而是通過定義一組接口,僅向上層暴露其接口功能,上層對于下層僅僅是接口依賴,而不依賴具體類。這樣做的好處是顯而易見的,首先對系統(tǒng)靈活性大有好處。當下層需要改變時,只要接口及接口功能不變,則上層不用做任何修改。甚至可以在不改動上層代碼時將下層整個替換掉,就像我們將一個WD的60G硬盤換成一個希捷的160G的硬盤,計算機其他地方不用做任何改動,而是把原硬盤拔下來、新硬盤插上就行了,因為計算機其他部分不依賴具體硬盤,而只依賴一個IDE接口,只要硬盤實現(xiàn)了這個接口,就可以替換上去。從
8、這里看,程序中的接口和現(xiàn)實中的接口極為相似,所以我一直認為,接口(interface)這個詞用的真是神似!使用接口的另一個好處就是不同部件或?qū)哟蔚拈_發(fā)人員可以并行開工,就像造硬盤的不用等造CPU的,也不用等造顯示器的,只要接口一致,設(shè)計合理,完全可以并行進行開發(fā),從而提高效率。本篇文章先到這里。最后我想再啰嗦一句:面向?qū)ο蟮木枋悄M現(xiàn)實,這也可以說是我這篇文章的靈魂。所以,多從現(xiàn)實中思考面向?qū)ο蟮臇|西,對提高系統(tǒng)分析設(shè)計能力大有脾益。下篇文章,我將用一個實例來展示接口編程的基本方法。而第三篇,我將解析經(jīng)典設(shè)計模式中的一些面向接口編程思想,并解析一下.NET分層架構(gòu)中的面向接口思想。對本文的補
9、充:仔細看了各位的回復,非常高興能和大家一起討論技術(shù)問題。感謝給出肯定的朋友,也要感謝提出意見和質(zhì)疑的朋友,這促使我更深入思考一些東西,希望能借此進步。在這里我想補充一些東西,以討論一些回復中比較集中的問題。1.關(guān)于“面向接口編程”中的“接口”與具體面向?qū)ο笳Z言中“接口”兩個詞看到有朋友提出“面向接口編程”中的“接口”二字應(yīng)該比單純編程語言中的interface范圍更大。我經(jīng)過思考,覺得很有道理。這里我寫的確實不太合理。我想,面向?qū)ο笳Z言中的“接口”是指具體的一種代碼結(jié)構(gòu),例如C#中用interface關(guān)鍵字定義的接口。而“面向接口編程”中的“接口”可以說是一種從軟件架構(gòu)的角度、從一個更抽象的
10、層面上指那種用于隱藏具體底層類和實現(xiàn)多態(tài)性的結(jié)構(gòu)部件。從這個意義上說,如果定義一個抽象類,并且目的是為了實現(xiàn)多態(tài),那么我認為把這個抽象類也稱為“接口”是合理的。但是用抽象類實現(xiàn)多態(tài)合理不合理?在下面第二條討論。概括來說,我覺得兩個“接口”的概念既相互區(qū)別又相互聯(lián)系?!懊嫦蚪涌诰幊獭敝械慕涌谑且环N思想層面的用于實現(xiàn)多態(tài)性、提高軟件靈活性和可維護性的架構(gòu)部件,而具體語言中的“接口”是將這種思想中的部件具體實施到代碼里的手段。2.關(guān)于抽象類與接口看到回復中這是討論的比較激烈的一個問題。很抱歉我考慮不周沒有在文章中討論這個問題。我個人對這個問題的理解如下:如果單從具體代碼來看,對這兩個概念很容易模糊,
11、甚至覺得接口就是多余的,因為單從具體功能來看,除多重繼承外(C#,Java中),抽象類似乎完全能取代接口。但是,難道接口的存在是為了實現(xiàn)多重繼承?當然不是。我認為,抽象類和接口的區(qū)別在于使用動機。使用抽象類是為了代碼的復用,而使用接口的動機是為了實現(xiàn)多態(tài)性。所以,如果你在為某個地方該使用接口還是抽象類而猶豫不決時,那么可以想想你的動機是什么??吹接信笥褜Person這個接口的質(zhì)疑,我個人的理解是,IPerson這個接口該不該定義,關(guān)鍵看具體應(yīng)用中是怎么個情況。如果我們的項目中有Women和Man,都繼承Person,而且Women和Man絕大多數(shù)方法都相同,只有一個方法DoSomething
12、InWC()不同(例子比較粗俗,各位見諒),那么當然定義一個AbstractPerson抽象類比較合理,因為它可以把其他所有方法都包含進去,子類只定義DoSomethingInWC(),大大減少了重復代碼量。但是,如果我們程序中的Women和Man兩個類基本沒有共同代碼,而且有一個PersonHandle類需要實例化他們,并且不希望知道他們是男是女,而只需把他們當作人看待,并實現(xiàn)多態(tài),那么定義成接口就有必要了??偠灾?,接口與抽象類的區(qū)別主要在于使用的動機,而不在于其本身。而一個東西該定義成抽象類還是接口,要根據(jù)具體環(huán)境的上下文決定。再者,我認為接口和抽象類的另一個區(qū)別在于,抽象類和它的子類之
13、間應(yīng)該是一般和特殊的關(guān)系,而接口僅僅是它的子類應(yīng)該實現(xiàn)的一組規(guī)則。(當然,有時也可能存在一般與特殊的關(guān)系,但我們使用接口的目的不在這里)如,交通工具定義成抽象類,汽車、飛機、輪船定義成子類,是可以接受的,因為汽車、飛機、輪船都是一種特殊的交通工具。再譬如Icomparable接口,它只是說,實現(xiàn)這個接口的類必須要可以進行比較,這是一條規(guī)則。如果Car這個類實現(xiàn)了Icomparable,只是說,我們的Car中有一個方法可以對兩個Car的實例進行比較,可能是比哪輛車更貴,也可能比哪輛車更大,這都無所謂,但我們不能說“汽車是一種特殊的可以比較”,這在文法上都不通。問題的提出 定義:現(xiàn)在我們
14、要開發(fā)一個應(yīng)用,模擬移動存儲設(shè)備的讀寫,即計算機與U盤、MP3、移動硬盤等設(shè)備進行數(shù)據(jù)交換。上下文(環(huán)境):已知要實現(xiàn)U盤、MP3播放器、移動硬盤三種移動存儲設(shè)備,要求計算機能同這三種設(shè)備進行數(shù)據(jù)交換,并且以后可能會有新的第三方的移動存儲設(shè)備,所以計算機必須有擴展性,能與目前未知而以后可能會出現(xiàn)的存儲設(shè)備進行數(shù)據(jù)交換。各個存儲設(shè)備間讀、寫的實現(xiàn)方法不同,U盤和移動硬盤只有這兩個方法,MP3Player還有一個PlayMusic方法。名詞定義:數(shù)據(jù)交換=讀,寫看到上面的問題,我想各位腦子中一定有了不少想法,這是個很好解決的問題,很多方案都能達到效果。下面,我列舉幾個典型的方案。解決方案列舉方案一
15、:分別定義FlashDisk、MP3Player、MobileHardDisk三個類,實現(xiàn)各自的Read和Write方法。然后在Computer類中實例化上述三個類,為每個類分別寫讀、寫方法。例如,為FlashDisk寫ReadFromFlashDisk、WriteToFlashDisk兩個方法??偣擦鶄€方法。方案二:定義抽象類MobileStorage,在里面寫虛方法Read和Write,三個存儲設(shè)備繼承此抽象類,并重寫Read和Write方法。Computer類中包含一個類型為MobileStorage的成員變量,并為其編寫get/set器,這樣Computer中只需要兩個方法:ReadD
16、ata和WriteData,并通過多態(tài)性實現(xiàn)不同移動設(shè)備的讀寫。方案三:與方案二基本相同,只是不定義抽象類,而是定義接口IMobileStorage,移動存儲器類實現(xiàn)此接口。Computer中通過依賴接口IMobileStorage實現(xiàn)多態(tài)性。方案四:定義接口IReadable和IWritable,兩個接口分別只包含Read和Write,然后定義接口IMobileStorage接口繼承自IReadable和IWritable,剩下的實現(xiàn)與方案三相同。下面,我們來分析一下以上四種方案:首先,方案一最直白,實現(xiàn)起來最簡單,但是它有一個致命的弱點:可擴展性差?;蛘哒f,不符合“開放-關(guān)閉原則”(注:意
17、為對擴展開放,對修改關(guān)閉)。當將來有了第三方擴展移動存儲設(shè)備時,必須對Computer進行修改。這就如在一個真實的計算機上,為每一種移動存儲設(shè)備實現(xiàn)一個不同的插口、并分別有各自的驅(qū)動程序。當有了一種新的移動存儲設(shè)備后,我們就要將計算機大卸八塊,然后增加一個新的插口,在編寫一套針對此新設(shè)備的驅(qū)動程序。這種設(shè)計顯然不可取。此方案的另一個缺點在于,冗余代碼多。如果有100種移動存儲,那我們的Computer中豈不是要至少寫200個方法,這是不能接受的!我們再來看方案二和方案三,之所以將這兩個方案放在一起討論,是因為他們基本是一個方案(從思想層面上來說),只不過實現(xiàn)手段不同,一個是使用了抽象類,一個是
18、使用了接口,而且最終達到的目的應(yīng)該是一樣的。我們先來評價這種方案:首先它解決了代碼冗余的問題,因為可以動態(tài)替換移動設(shè)備,并且都實現(xiàn)了共同的接口,所以不管有多少種移動設(shè)備,只要一個Read方法和一個Write方法,多態(tài)性就幫我們解決問題了。而對第一個問題,由于可以運行時動態(tài)替換,而不必將移動存儲類硬編碼在Computer中,所以有了新的第三方設(shè)備,完全可以替換進去運行。這就是所謂的“依賴接口,而不是依賴與具體類”,不信你看看,Computer類只有一個MobileStorage類型或IMobileStorage類型的成員變量,至于這個變量具體是什么類型,它并不知道,這取決于我們在運行時給這個變量
19、的賦值。如此一來,Computer和移動存儲器類的耦合度大大下降。那么這里該選抽象類還是接口呢?還記得第一篇文章我對抽象類和接口選擇的建議嗎?看動機。這里,我們的動機顯然是實現(xiàn)多態(tài)性而不是為了代碼復用,所以當然要用接口。最后我們再來看一看方案四,它和方案三很類似,只是將“可讀”和“可寫”兩個規(guī)則分別抽象成了接口,然后讓IMobileStorage再繼承它們。這樣做,顯然進一步提高了靈活性,但是,這有沒有設(shè)計過度的嫌疑呢?我的觀點是:這要看具體情況。如果我們的應(yīng)用中可能會出現(xiàn)一些類,這些類只實現(xiàn)讀方法或只實現(xiàn)寫方法,如只讀光盤,那么這樣做也是可以的。如果我們知道以后出現(xiàn)的東西都是能讀又能寫的,那
20、這兩個接口就沒有必要了。其實如果將只讀設(shè)備的Write方法留空或拋出異常,也可以不要這兩個接口??傊痪湓挘豪碚撌撬赖?,人是活的,一切從現(xiàn)實需要來,防止設(shè)計不足,也要防止設(shè)計過度。在這里,我們姑且認為以后的移動存儲都是能讀又能寫的,所以我們選方案三。實現(xiàn)下面,我們要將解決方案加以實現(xiàn)。我選擇的語言是C#,但是在代碼中不會用到C#特有的性質(zhì),所以使用其他語言的朋友一樣可以參考。首先編寫IMobileStorage接口:Code:IMobileStorage1namespace InterfaceExample23 public i
21、nterface IMobileStorage4 5 void Read();/從自身讀數(shù)據(jù)6 void Write();/將數(shù)據(jù)寫入自身7 8 代碼比較簡單,只有兩個方法,沒什么好說的,接下來是三個移動存儲設(shè)備的具體實現(xiàn)代碼:U盤Code:FlashDisk 1nam
22、espace InterfaceExample 2 3 public class FlashDisk : IMobileStorage 4 5 public void Read() 6
23、7 Console.WriteLine("Reading from FlashDisk"); 8 Console.WriteLine("Read finished!"); 9
24、160; 1011 public void Write()12 13 Console.WriteLine("Writing to FlashDisk");14
25、60; Console.WriteLine("Write finished!");15 16 17MP3Code:MP3Player 1namespace InterfaceExample 2 3 public cl
26、ass MP3Player : IMobileStorage 4 5 public void Read() 6 7 Console
27、.WriteLine("Reading from MP3Player"); 8 Console.WriteLine("Read finished!"); 9 1011 public
28、 void Write()12 13 Console.WriteLine("Writing to MP3Player");14 Console.WriteLine
29、("Write finished!");15 1617 public void PlayMusic()18 19 Consol
30、e.WriteLine("Music is playing");20 21 22移動硬盤Code:MobileHardDisk 1namespace InterfaceExample 2 3 public class MobileHardDisk : IMobileStorage 4
31、 5 public void Read() 6 7 Console.WriteLine("Reading from MobileHardDi
32、sk"); 8 Console.WriteLine("Read finished!"); 9 1011 public void Write()12
33、0; 13 Console.WriteLine("Writing to MobileHardDisk");14 Console.WriteLine("Write finished!");15
34、; 16 17可以看到,它們都實現(xiàn)了IMobileStorage接口,并重寫了各自不同的Read和Write方法。下面,我們來寫Computer:Code:Computer 1namespace InterfaceExample 2 3 public class Computer 4 5
35、; private IMobileStorage _usbDrive; 6 7 public IMobileStorage UsbDrive 8 9
36、160; get10 11 return this._usbDrive;12 13
37、 set14 15 this._usbDrive = value;16
38、 17 1819 public Computer()20 21 2223
39、 public Computer(IMobileStorage usbDrive)24 25 this.UsbDrive = usbDrive;26 27
40、60; 28 public void ReadData()29 30 this._usbDrive.Read();31 3233
41、60; public void WriteData()34 35 this._usbDrive.Write();36 37
42、;38其中的UsbDrive就是可替換的移動存儲設(shè)備,之所以用這個名字,是為了讓大家覺得直觀,就像我們平常使用電腦上的USB插口插拔設(shè)備一樣。OK!下面我們來測試我們的“電腦”和“移動存儲設(shè)備”是否工作正常。我是用的C#控制臺程序,具體代碼如下:Code:測試代碼 1namespace InterfaceExample 2 3 class Program 4 5
43、 static void Main(string args) 6 7 Computer computer = new Computer(); 8
44、 IMobileStorage mp3Player = new MP3Player(); 9 IMobileStorage flashDisk = new FlashDisk();10
45、60;IMobileStorage mobileHardDisk = new MobileHardDisk();1112 Console.WriteLine("I inserted my MP3 Player into my computer and copy some music to
46、 it:");13 computer.UsbDrive = mp3Player;14 computer.WriteData();15
47、Console.WriteLine();1617 Console.WriteLine("Well,I also want to copy a great movie to my computer from a mobile hard disk:");18
48、; computer.UsbDrive = mobileHardDisk;19 computer.ReadData();20 Console.WriteLine();2122
49、160; Console.WriteLine("OK!I have to read some files from my flash disk and copy another file to it:");23
50、60; computer.UsbDrive = flashDisk;24 computer.ReadData();25 computer.WriteData();26
51、 Console.ReadLine();27 28 29現(xiàn)在編譯、運行程序,如果沒有問題,將看到如下運行結(jié)果:圖2.1 各種移動存儲設(shè)備測試結(jié)果好的,看來我們的系統(tǒng)工作良好。后來 剛過了一個星期,就有人送來了新的移動存儲設(shè)備NewMobileStorage,讓我測試能不能用,我微微一笑,心想這不是小菜一碟,讓我們看看面向接口編程的威力吧!將測試程序修改成如下:Code:測試代碼 1names
52、pace InterfaceExample 2 3 class Program 4 5 static void Main(string args) 6 7
53、160; Computer computer = new Computer(); 8 IMobileStorage newMobileStorage = new NewMobileStorage(); 910
54、0; Console.WriteLine("Now,I am testing the new mobile storage:");11 computer.UsbDrive = newMobileStorage;12 &
55、#160; computer.ReadData();13 computer.WriteData();14 Console.ReadLine();15 16
56、; 17編譯、運行、看結(jié)果:哈哈,神奇吧,Computer一點都不用改動,就可以使新的設(shè)備正常運行。這就是所謂“對擴展開放,對修改關(guān)閉”。圖2.2 新設(shè)備擴展測試結(jié)果又過了幾天,有人通知我說又有一個叫SuperStorage的移動設(shè)備要接到我們的Computer上,我心想來吧,管你是“超級存儲”還是“特級存儲”,我的“面向接口編程大法”把你們統(tǒng)統(tǒng)搞定。但是,當設(shè)備真的送來,我傻眼了,開發(fā)這個新設(shè)備的團隊沒有拿到我們的IMobileStorage接口,自然也沒有遵照這個約定。這個設(shè)備的讀、寫方法不叫Read和Write,而是叫rd和wt,這下完了不符合接口啊,插
57、不上。但是,不要著急,我們回到現(xiàn)實來找找解決的辦法。我們一起想想:如果你的Computer上只有USB接口,而有人拿來一個PS/2的鼠標要插上用,你該怎么辦?想起來了吧,是不是有一種叫“PS/2-USB”轉(zhuǎn)換器的東西?也叫適配器,可以進行不同接口的轉(zhuǎn)換。對了!程序中也有轉(zhuǎn)換器。這里,我要引入一個設(shè)計模式,叫“Adapter”。它的作用就如現(xiàn)實中的適配器一樣,把接口不一致的兩個插件接合起來。由于本篇不是講設(shè)計模式的,而且Adapter設(shè)計模式很好理解,所以我就不細講了,先來看我設(shè)計的類圖吧:如圖所示,雖然SuperStorage沒有實現(xiàn)IMobileStorage,但我們定義了一個實現(xiàn)IMobi
58、leStorage的SuperStorageAdapter,它聚合了一個SuperStorage,并將rd和wt適配為Read和Write,SuperStorageAdapter圖2.3 Adapter模式應(yīng)用示意具體代碼如下:Code:SuperStorageAdapter 1namespace InterfaceExample 2 3 public class SuperStorageAdapter : IMobileStorage 4
59、0; 5 private SuperStorage _superStorage; 6 7 public SuperStorage SuperStorage 8 9
60、160; get10 11 return this._superStorage;12
61、0; 13 set14 15 this._superStorage&
62、#160;= value;16 17 18 19 public void Read()20 21
63、160; this._superStorage.rd();22 2324 public void Write()25 26
64、; this._superStorage.wt();27 28 29好,現(xiàn)在我們來測試適配過的新設(shè)備,測試代碼如下:Code:測試代碼 1namespace InterfaceExample 2 3 class Program 4
65、60; 5 static void Main(string args) 6 7 Computer computer = new Computer();
66、60;8 SuperStorageAdapter superStorageAdapter = new SuperStorageAdapter(); 9 SuperStorage superStorage = new Super
67、Storage();10 superStorageAdapter.SuperStorage = superStorage;1112 Console.WriteLine("Now,I am testing the new super
68、60;storage with adapter:");13 computer.UsbDrive = superStorageAdapter;14 computer.ReadData();15 computer.WriteData();16
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高處作業(yè)圖紙審查方案
- 成人教育“停課不停學”遠程學習方案
- 防雷系統(tǒng)綜合安裝項目協(xié)議范本2024
- 牛羊流行病學調(diào)查方案
- 2024年度企業(yè)產(chǎn)品銷售協(xié)議
- 2024年化代建合作協(xié)議模板
- 網(wǎng)絡(luò)市場營銷合同
- 家庭安保服務(wù)合同說明
- 特教教師職稱評定工作方案
- 公寓樓施工組織設(shè)計
- 中華人民共和國傳染病防治法-李碩娟 陳桂云
- 2023-2024年江蘇省數(shù)學競賽初賽試題(原題 詳解)
- 成本轉(zhuǎn)嫁方案
- 貴醫(yī)研究353衛(wèi)生綜合真題(完整)
- ARDS機械通氣參數(shù)設(shè)置:小潮氣量、低平臺壓、高PEEP
- 幼兒園食譜播報
- 文言文司馬遷《屈原賈生列傳》司馬遷《報任安書》閱讀練習及答案
- 政府采購行業(yè)營銷策略方案
- Unit6Craftsmanship+單詞課件-中職高二英語高教版(2021)基礎(chǔ)模塊2
- 蘇教版小學數(shù)學六年級上冊第4單元解決問題的策略重難點練習【含答案】
- 2023-2024年新人教版pep六年級英語上冊試卷全套含答案
評論
0/150
提交評論