302班

          java突擊隊(duì)
          posts - 151, comments - 74, trackbacks - 0, articles - 14
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
          Java語(yǔ)言提供了一種接口(interface)機(jī)制。這種接口機(jī)制使Java的面向?qū)ο缶幊套兊酶屿`活。我們可以用接口來(lái)定義一個(gè)類(lèi)的表現(xiàn)形式,但接口不能包含任何實(shí)現(xiàn)。在《Thinking in Java》一書(shū)中,作者對(duì)接口有這樣的描述:“接口(interface)比抽象(abstract)的概念更進(jìn)了一步。你可以把一個(gè)接口看成是一個(gè)純的抽象類(lèi)。”我認(rèn)為作者對(duì)接口的這一解釋再準(zhǔn)確不過(guò)了。

            理解并用好接口機(jī)制將幫助我們更好的掌握J(rèn)ava這種面向?qū)ο蟮木幊陶Z(yǔ)言。下面我們來(lái)討論一下接口的使用規(guī)則以及相關(guān)的應(yīng)用。

            一、接口的定義及實(shí)現(xiàn)

             定義接口和定義類(lèi)相似,只是要把 class關(guān)鍵字換為 interface。定義方法時(shí)只需要方法名,返回類(lèi)型和參數(shù)列表,不能有方法體。接口中可以定義字段,這些字段都被暗指為 static 和 final,因此應(yīng)該根據(jù)需要先定好這些字段的值。例如:

            public interface Flyable {
            void fly();
            }

            public interface Talkable {
            void talk();
            }

            public interface Message {
            int MAX_SIZE = 4096;
            String getMessage();
            }

            上面定義的幾個(gè)接口中,F(xiàn)lyable 和 Talkable 只定義了一個(gè)方法,而 Message 里除了方法外還有一個(gè)字段 MAX_SIZE。可以看出這些接口只定義了類(lèi)的表現(xiàn)形式,而不包含任何實(shí)現(xiàn),所以不能直接使用。要使用這些接口就需要有相應(yīng)的類(lèi)去實(shí)現(xiàn)它們。實(shí)現(xiàn)接口時(shí)應(yīng)該先在類(lèi)名后用 implements 關(guān)鍵字申明將要實(shí)現(xiàn)的接口,如果要實(shí)現(xiàn)多個(gè)接口,應(yīng)該用逗號(hào)將它們隔開(kāi),然后一一實(shí)現(xiàn)這些接口中定義的方法。如下面的例子:

            public class Parrot implements Flyable, Talkable {

            public void fly() {
            System.out.println("Flying like a parrot…");
            }

            public void talk() {
            System.out.println("Hello! I am a parrot!");
            }
            }

            public class TextMessage implements Message {
            String message;

            public void setMessage(String msg) {
            message = msg;
            if (message.length() > MAX_SIZE)
            message = message.substring(0, MAX_SIZE);
            }

            public String getMessage() {
            return message;
            }
            }

            在 Parrot(鸚鵡)例子中,我們用接口 Flyable 來(lái)表示飛行能力,Talkable 表示說(shuō)話能力,但它們并不包含具體實(shí)現(xiàn)。而 Parrot 同時(shí)具有這兩種能力,所以我們?yōu)?Parrot 類(lèi)同時(shí)實(shí)現(xiàn)了 Flyable 和 Talkable 這兩個(gè)接口。同樣我們還可以定義一個(gè)Swallow(燕子)類(lèi),但燕子只有飛行能力,所以我們只需要為 Swallow 實(shí)現(xiàn) Flyable 就行了。因?yàn)樗鼈兏髯缘牡娘w行方法有所不同,所以它們有各自關(guān)于飛行的具體實(shí)現(xiàn)。

             另外,正因?yàn)橐粋€(gè)類(lèi)可以同時(shí)實(shí)現(xiàn)多個(gè)接口,使得Java的面向?qū)ο筇匦宰兊梅浅l`活。運(yùn)用這種特性,我們可以實(shí)現(xiàn)類(lèi)似C++語(yǔ)言中多繼承那樣的特性,甚至更靈活的一些特性。下面我們來(lái)討論一下接口在實(shí)際中的應(yīng)用。

            二、用接口來(lái)定義一些全局變量

             因?yàn)榻涌趦?nèi)的字段都是static和final的,所以我們可以很方便的利用這一點(diǎn)來(lái)創(chuàng)建一些常量。例如:

            public interface Constants {
            String ROOT = "/root";
            int MAX_COUNT = 200;
            int MIN_COUNT = 100;
            }

            在使用時(shí)可以直接用Constants.ROOT這樣的形式來(lái)引用其中的常量。我們還可以用下面這種方法來(lái)創(chuàng)建初始值不確定的常量。

            public interface RandomColor {
            int red = Math.random() * 255;
            int green = Math.random() * 255;
            int blue = Math.random() * 255;
            }


            其中red、green和blue的值會(huì)在第一次被訪問(wèn)時(shí)建立,然后保持不變。

             三、用接口來(lái)定義基本數(shù)據(jù)結(jié)構(gòu)

             在設(shè)計(jì)一套軟件系統(tǒng)的初期,我們可以用接口來(lái)對(duì)一些基本數(shù)據(jù)元素的特性來(lái)進(jìn)行一些描述,再根據(jù)需要進(jìn)行不同的實(shí)現(xiàn)。請(qǐng)大家看看下面這個(gè)例子:

            public interface User {
            int getAge();
            String getName();
            String getPassword();
            }

            public class XMLUser implements User {
            // 這里用XML技術(shù)實(shí)現(xiàn)User接口中的方法
            public int getAge() { ... }
            public String getName() { ... }
            public String getPassword() { ... }
            }

            public abstract class UserFactory {
            public static UserFactory getUserFactory() {
            return new XMLUserFactory();
            }

            public User getUser(String name);
            public User getAdmin();
            public User createUser(String name, String password, int age);
            public void addUser(User user);
            public void delUser(User user);
            }

            public class XMLUserFactory extends UserFactory {
            // 這里用XML技術(shù)實(shí)現(xiàn)的UserFactory的抽象方法
            }

            在這個(gè)例子中,我們定義了一個(gè)接口User和一個(gè)抽象類(lèi)UserFactory。然后我們用XML技術(shù)實(shí)現(xiàn)這兩個(gè)類(lèi)。可以看出,我們只需要從用UserFactory的getUserFactory()就可以得到一個(gè)UserFactory的實(shí)例,而不用去考慮這個(gè)實(shí)例的具體實(shí)現(xiàn)方法。通過(guò)UserFactory的這個(gè)實(shí)例我們還可以直接得到User的實(shí)例,也不用去考具體的實(shí)現(xiàn)方法。

            如果我們決定用JDBC技術(shù)來(lái)實(shí)現(xiàn)User和UserFactory,我們只需要按上面的形式實(shí)現(xiàn)JDBCUser和JDBCUserFactory就行了。然后把UserFactory中的getUserFactory方法修改一下就可以改變了它們的實(shí)現(xiàn)方法。而我們已經(jīng)寫(xiě)好的調(diào)用UserFactory和User的部分不需要做任何修改。

            這是用接口來(lái)定義數(shù)據(jù)結(jié)構(gòu)的一個(gè)簡(jiǎn)單的例子,在實(shí)際應(yīng)用中還有很多靈活的使用方法,大家需要在學(xué)習(xí)過(guò)程中不斷的去體會(huì)。

            四、理解分布式應(yīng)用的原理

            目前有很多軟件項(xiàng)目都使用了分布式的技術(shù)。Java 有多種支持分布式應(yīng)用的技術(shù),早期用的比較多的有 RMI、CORBA 等技術(shù),而現(xiàn)在 EJB 技術(shù)更為流行一些。但這些技術(shù)不管怎么發(fā)展,其實(shí)都是以接口為基礎(chǔ)的。

            以遠(yuǎn)程方法調(diào)用 RMI(Remote Method Invocation)為例。在編寫(xiě) RMI 應(yīng)用時(shí),我們需要做兩件最基本的事,首先要定義一個(gè)接口,這個(gè)接口要繼承 java.rmi.Remote 接口,這個(gè)接口中應(yīng)該包含你要從遠(yuǎn)端調(diào)用的方法名。接下來(lái)就是寫(xiě)一個(gè)類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口中的方法。例如:

            public interface Product extends java.rmi.Remote {
            String getName() throws java.rmi.RemoteException;
            }

            public class ProductImpl implements Product {
            String name;

            public ProductImpl(String n) {
            name = n;
            }

            public String getName() throws java.rmi.RemoteException {
            return name;
            }
            }

            在這個(gè)例子中,接口 Product 是放在客戶(hù)端的,而 ProductImpl 是放在服務(wù)器端的,客戶(hù)在使用時(shí)只需要用指定的規(guī)則得到Product 的實(shí)例就行了,不用去考慮 Product 接口里的方法是如何實(shí)現(xiàn)的。在定義好這兩個(gè)類(lèi)后,用Java開(kāi)發(fā)包命令“rmic ProductImpl”就可以幫助我們自動(dòng)生成兩個(gè)類(lèi) ProductImpl_Skel 和 ProductImpl_Stub。這兩個(gè)類(lèi)就包含了RMI調(diào)用的運(yùn)作機(jī)制。有興趣的朋友可以把這兩個(gè)類(lèi)反編譯后研究一下。你會(huì)發(fā)現(xiàn)其中 ProductImpl_Stub 實(shí)際上是接口 Product 的一個(gè)實(shí)現(xiàn)類(lèi)。RMI 機(jī)制就是用這個(gè)類(lèi)來(lái)生成 Product 的實(shí)例供客戶(hù)端使用。另一個(gè)類(lèi) ProductImpl_Skel 則是在服務(wù)端響應(yīng) ProductImpl_Stub 的調(diào)用請(qǐng)求的類(lèi)。而 RMI 最底層的通訊原理則是利用 ObjectInputStream 和 ObjetOutputStream 通過(guò) Socket 將要調(diào)用的方法名及參數(shù)列表傳到服務(wù)器端,服務(wù)器端再通過(guò)特定的方法調(diào)用實(shí)現(xiàn)類(lèi)(在本例中是 ProductImpl)的對(duì)應(yīng)方法,然后將結(jié)果通過(guò) Socket 傳回客戶(hù)端就行了。由于 Skel 和 Stub 類(lèi)是用工具生成的,所以就大大節(jié)省了開(kāi)發(fā)的時(shí)間。另外,如果我們需要修改一些實(shí)現(xiàn)方法或錯(cuò)誤,只需要對(duì)服務(wù)器端的實(shí)現(xiàn)類(lèi)進(jìn)行修改就可以了,也就是說(shuō)這種分布式應(yīng)用的大部分維護(hù)工作在服務(wù)器端就可以完成。

             現(xiàn)在越來(lái)越多的應(yīng)用使用了 EJB 這種技術(shù)。EJB 是從 RMI 發(fā)展而來(lái)的一項(xiàng)技術(shù),它比RMI定義得更加完善,可以獲得更好的面向?qū)ο蟮奶匦浴5囊?guī)則要比RMI復(fù)雜一些。但是不管它多復(fù)雜,它同樣是使用了接口來(lái)定義各種不同的 Bean,也同樣需要編寫(xiě)相應(yīng)的實(shí)現(xiàn)類(lèi)來(lái)完成具體的功能,最后還要通過(guò) Socket 來(lái)進(jìn)行通訊。EJB的運(yùn)作機(jī)制本身有一定的復(fù)雜性,所以其應(yīng)用的效率理所當(dāng)然就會(huì)受到一定的影響。因此在選擇開(kāi)發(fā)技術(shù)時(shí)應(yīng)該根據(jù)應(yīng)用的規(guī)模和特點(diǎn)仔細(xì)考慮,不一定流行的技術(shù)就一定能適應(yīng)你的應(yīng)用。如果你很好的掌握了面向?qū)ο蟮脑O(shè)計(jì)原則,你就可以自行設(shè)計(jì)。也許你可以根據(jù)自己應(yīng)用的特點(diǎn)設(shè)計(jì)出更合適的分布式應(yīng)用結(jié)構(gòu)。

            五、結(jié)論

            除了上述的一些應(yīng)用外,還有很多地方可以使用接口,比如在Java的事件機(jī)制中就常用到接口。另外,對(duì)于一些已經(jīng)開(kāi)發(fā)好的系統(tǒng),在結(jié)構(gòu)上進(jìn)行較大的調(diào)整已經(jīng)不太現(xiàn)實(shí),這時(shí)可以通過(guò)定義一些接口并追加相應(yīng)的實(shí)現(xiàn)來(lái)完成功能結(jié)構(gòu)的擴(kuò)展。

            總之,學(xué)好接口可以幫助我們更好的理解和運(yùn)用面向?qū)ο蟮脑O(shè)計(jì)原則。使我們能設(shè)計(jì)出更好的軟件系統(tǒng)。由于本人水平的限制,如有錯(cuò)誤之處還請(qǐng)多多指正。


          評(píng)論

          # re: Java程序設(shè)計(jì)中的接口應(yīng)用   回復(fù)  更多評(píng)論   

          2007-06-16 14:39 by itkui
          哎,接口就是理解不透。。。

          # re: Java程序設(shè)計(jì)中的接口應(yīng)用   回復(fù)  更多評(píng)論   

          2007-06-16 18:14 by 停留的風(fēng)
          @itkui
          那就簡(jiǎn)單的理解哦,interface 其實(shí)也是class,只是里面的方法都是抽象的,可以說(shuō)是多種事務(wù)將其共同點(diǎn)抽象出來(lái),定義一個(gè)方法,那么就可以組成一個(gè)抽象類(lèi)哦。完全抽象的類(lèi)就是interface。

          # re: Java程序設(shè)計(jì)中的接口應(yīng)用   回復(fù)  更多評(píng)論   

          2007-08-01 09:36 by ltw
          為什么有的事件要實(shí)現(xiàn)接口,而有的不用實(shí)現(xiàn)呢(Buttn的actionPerformed)

          # re: Java程序設(shè)計(jì)中的接口應(yīng)用   回復(fù)  更多評(píng)論   

          2007-08-04 20:39 by you
          @ltw
          這就看你實(shí)現(xiàn)什么功能啦,如果父類(lèi)有這些接口我們可以實(shí)現(xiàn)它。如果你實(shí)現(xiàn)了接口,里面的所有方法都要實(shí)現(xiàn)

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 来宾市| 门头沟区| 吴江市| 鹤山市| 屏南县| 唐山市| 犍为县| 晋中市| 淮南市| 德兴市| 曲水县| 察隅县| 通道| 宾川县| 灵寿县| 裕民县| 宝兴县| 沭阳县| 中西区| 商洛市| 治多县| 嘉祥县| 黄大仙区| 深水埗区| 普格县| 昌图县| 西林县| 灌南县| 保靖县| 徐水县| 郸城县| 海林市| 菏泽市| 永宁县| 景谷| 四平市| 栾川县| 固始县| 桂平市| 文昌市| 舞阳县|