FactoryMethod模式在Javamail中的應(yīng)用

字號(hào):

設(shè)計(jì)模式在軟件工程中占有重要地位,而JavaMail是Java平臺(tái)的一個(gè)擴(kuò)展,為管理電子郵件提供了統(tǒng)一的應(yīng)用編程接口。本文討論Factory Method設(shè)計(jì)模式在Javamail中的應(yīng)用。
    1、模式簡(jiǎn)介
    模式的概念最早是出現(xiàn)在城市建筑領(lǐng)域的。lexander的一本關(guān)于建筑的書(shū)中明確的給出了模式的概念,用來(lái)解決在建筑中的一些問(wèn)題。后來(lái),這個(gè)概念逐漸的被計(jì)算機(jī)科學(xué)所采納。《Design Patterns: Elements of Reusable Object-Oriented Software》[1](以下簡(jiǎn)稱(chēng)《設(shè)計(jì)模式》)則堪稱(chēng)設(shè)計(jì)模式領(lǐng)域的經(jīng)典書(shū)籍之一。它開(kāi)創(chuàng)了軟件工程領(lǐng)域的模式化進(jìn)程。
    設(shè)計(jì)模式的簡(jiǎn)單定義就是對(duì)于一類(lèi)重復(fù)出現(xiàn)的問(wèn)題的可重用的解決方案。在軟件工程中一個(gè)設(shè)計(jì)模式解決一類(lèi)軟件設(shè)計(jì)問(wèn)題。設(shè)計(jì)模式中許多方法其實(shí)很早就出現(xiàn)了,并且在應(yīng)用中也比較多。但是直到《設(shè)計(jì)模式》出來(lái)之前,并沒(méi)有一種統(tǒng)一的認(rèn)識(shí)?;蛘哒f(shuō),那時(shí)候并沒(méi)有對(duì)模式形成一個(gè)概念。這些方法還僅僅是處在經(jīng)驗(yàn)階段,并沒(méi)有能夠被系統(tǒng)的整理,形成一種理論。
    每一個(gè)設(shè)計(jì)模式都系統(tǒng)的命名,解釋和評(píng)價(jià)了面向?qū)ο笙到y(tǒng)中的一個(gè)重要的和重復(fù)出現(xiàn)的設(shè)計(jì)。這樣,我們只要搞清楚這些設(shè)計(jì)模式,就可以完全或者說(shuō)很大程度上吸收了那些蘊(yùn)含在模式中的寶貴的經(jīng)驗(yàn),對(duì)面向?qū)ο蟮南到y(tǒng)能夠有更為完善的了解。更為重要的是,這些模式都可以直接用來(lái)指導(dǎo)面向?qū)ο笙到y(tǒng)中至關(guān)重要的對(duì)象建模問(wèn)題。如果有相同的問(wèn)題背景,那么很簡(jiǎn)單,直接套用這些模式就可以了。這可以省去你很多的工作。
    在《設(shè)計(jì)模式》一書(shū)中涉及到23個(gè)模式,被分類(lèi)為創(chuàng)建型模式(Creational Patterns),結(jié)構(gòu)型模式(Structural Patterns)和行為模式(Behavioral Patterns),分別從對(duì)象的創(chuàng)建,對(duì)象和對(duì)象間的結(jié)構(gòu)組合以及對(duì)象交互這三個(gè)方面為面向?qū)ο笙到y(tǒng)建模方法給予了解析和指導(dǎo)。
    其中創(chuàng)建型設(shè)計(jì)模式(Creational Patterns)描述怎樣創(chuàng)建一個(gè)對(duì)象。它隱藏對(duì)象創(chuàng)建的細(xì)節(jié),使程序代碼不依賴(lài)具體的對(duì)象,這樣當(dāng)我們?cè)黾右粋€(gè)新的對(duì)象時(shí)幾乎不需要修改代碼。結(jié)構(gòu)型設(shè)計(jì)模式(Structural Patterns)描述類(lèi)和對(duì)象之間怎么組織起來(lái)形成大的結(jié)構(gòu),主要使用繼承來(lái)組織接口或?qū)崿F(xiàn)。行為型設(shè)計(jì)模式(Behavioral Patterns)描述算法以及對(duì)象之間的任務(wù)分配,它所描述的不僅僅是對(duì)象或類(lèi)的設(shè)計(jì)模式,還有它們之間的通訊模式。
    設(shè)計(jì)模式在Java中得到了廣泛應(yīng)用。在《Thinking in Java》[3]一書(shū)中,Bruce Eckel介紹了Singleton、Prototype、Observer、Visitor等設(shè)計(jì)模式在Java中的具體應(yīng)用和實(shí)現(xiàn),以下將介紹 Factory Method設(shè)計(jì)模式在Javamail中的應(yīng)用。從中可看出設(shè)計(jì)模式不僅有助于軟件設(shè)計(jì),對(duì)理解軟件結(jié)構(gòu)也很有幫助。
    2、Javamail簡(jiǎn)介
    經(jīng)過(guò)幾年的發(fā)展,Java語(yǔ)言已相當(dāng)成熟,并在各領(lǐng)域得到廣泛應(yīng)用。特別是J2EETM(JavaTM 2 Platform, Enterprise Edition)的出現(xiàn),更是極大地方便了分布式應(yīng)用程序的創(chuàng)建。作為Java平臺(tái)的一個(gè)擴(kuò)展--JavaMail,也是J2EETM的技術(shù)之一,為管理電子郵件提供了統(tǒng)一的應(yīng)用編程接口(API,Application Programming Interface)。它使服務(wù)提供者(service providers)可以使用Java語(yǔ)言為它們自己的郵件或消息處理系統(tǒng)提供一致的接口,應(yīng)用程序可以使用這些一致的接口方便地與這些系統(tǒng)通信。
    以下是一些Javamail API中的抽象類(lèi),由它們可以組成典型的郵件系統(tǒng):
    Message-代表一個(gè)電子郵件消息。
    Folder-以分級(jí)的形式組織消息。一個(gè)Folder可以包含多條消息、多個(gè)Folder。
    Store-代表由郵件服務(wù)器 target=_blank>服務(wù)器管理的消息數(shù)據(jù)庫(kù),一個(gè)具體的Store使用一種特殊的訪(fǎng)問(wèn)協(xié)議(如Pop3Store使用Pop3協(xié)議,IMAPStore使用IMAP協(xié)議),并可包含一個(gè)或多個(gè)Folder。
    Transport-代表一個(gè)特殊的傳輸協(xié)議,一個(gè)具體的Transport使用具體的傳輸協(xié)議發(fā)送消息。
    3、設(shè)計(jì)模式Factory Method
    此模式屬于創(chuàng)建型設(shè)計(jì)模式,它只定義創(chuàng)建對(duì)象的接口,而由它的子類(lèi)負(fù)責(zé)創(chuàng)建具體的對(duì)象,利用子類(lèi)實(shí)例化不同的對(duì)象。Factory Method 模式結(jié)構(gòu)的類(lèi)圖(Class Diagram),其中:
    Product 定義了由factory method所創(chuàng)建對(duì)象的統(tǒng)一接口。
    ConcreteProduct 具體的類(lèi),實(shí)現(xiàn)Product接口。
    Creator 一般為抽象類(lèi),聲明若干factory method(方法),由它創(chuàng)建類(lèi)型為Product的對(duì)象。正因?yàn)樗?生產(chǎn)"對(duì)象,所以稱(chēng)為factory method。Creator也可能擁有一個(gè)方法創(chuàng)建某個(gè)缺省的具體對(duì)象。
    ConcreteCreator 重載factory method以創(chuàng)建某個(gè) ConcreteProduct 的具體實(shí)例。
    也就是說(shuō)Creator依賴(lài)于ConcreteCreator創(chuàng)建Product型的ConcreteProduct對(duì)象。 Factory method使應(yīng)用程序代碼只需處理Product接口,而與具體的類(lèi)(ConcreteProduct)無(wú)關(guān),增強(qiáng)了代碼可重用性,因?yàn)樗?dú)立于用戶(hù)定義的具體的類(lèi)。
    4、Factory Method在Javamail中的應(yīng)用
    Factory Method在Javamail中的應(yīng)用。其中的類(lèi)Store相當(dāng)于Creator,Store的兩個(gè)子類(lèi) Pop3Store,IMAPStore相當(dāng)于ConcreteStore,類(lèi)Folder相當(dāng)于Product,F(xiàn)older的兩個(gè)子類(lèi) Pop3Folder和IMAPFolder相當(dāng)于ConcreteProduct,而Store中的方法getFolder就是一個(gè)factory method,由子類(lèi)Pop3Store實(shí)例化Pop3Folder,由IMAPStore實(shí)例化IMAPFolder。
    類(lèi)似的Folder相對(duì)于Store來(lái)說(shuō)是Product,但相對(duì)于Messsage卻也是一個(gè)Creator,其方法getMessage同樣也是factory method。
    4.1可重用性
    上表是使用Factory Method模式創(chuàng)建對(duì)象和直接創(chuàng)建對(duì)象的比較,顯然前者對(duì)于創(chuàng)建不同的對(duì)象所用的代碼幾乎相同,便于代碼重用,而后者對(duì)于創(chuàng)建不同的對(duì)象所用代碼就相差很大,想做改動(dòng)就比較麻煩,若想重用就幾乎是不可能的。設(shè)計(jì)可重用的面向?qū)ο筌浖鞘植灰椎模‘?dāng)?shù)剡\(yùn)用設(shè)計(jì)模式則可在一定程度上解決這個(gè)問(wèn)題。
    4.2 可擴(kuò)展性
    如有一種對(duì)應(yīng)與Pop3、IMAP的新的郵件協(xié)議NewP,則很容易使系統(tǒng)支持這種新的協(xié)議,擴(kuò)展Store建立新類(lèi)NewPStore,擴(kuò)展 Folder建立新類(lèi)NewPFolder,擴(kuò)展Message建立新類(lèi)NewPMessage,就建立起了新協(xié)議的大致框架。
    5、Parameterized Factory Method在Javamail中的應(yīng)用
    Factroy Method設(shè)計(jì)模式還有一個(gè)變異Parameterized factory method模式。對(duì)于Parameterized factory method模式,其factory method有一參數(shù),用于指明需創(chuàng)建的對(duì)象的類(lèi)型,這樣一個(gè)類(lèi)的factory method可以創(chuàng)建多種具體類(lèi)型(ConcreteProduct)的對(duì)象,與Factory Method相同的是它所創(chuàng)建的對(duì)象都具有同樣的接口Product。
    在Javamail中有一個(gè)final static類(lèi)Session,不能創(chuàng)建它的子類(lèi),通過(guò)此類(lèi)設(shè)置和訪(fǎng)問(wèn)一些特殊的屬性,另外此類(lèi)還擁有若干Parameterized Factory Method,可以創(chuàng)建多種對(duì)象。
    5.1可重用性
    getStore和getTransport都是Parameterized Factory Method,以getStore為例,給參數(shù)以不同的值就能創(chuàng)建不同的對(duì)象。例如:
    1 Session session = Session.getDefaultInstance(props, authenticator);
    2
    3   Store store1 = session.getStore("pop3"); //實(shí)例化Pop3Store
    4
    5   Store store2 = session.getStore("IMAP"); //實(shí)例化IMAPStore
    6
    7
    如上代碼所示,通過(guò)給出不同的參數(shù),即能實(shí)例化不同的對(duì)象,其代碼重用是相當(dāng)簡(jiǎn)單的。
    5.2可擴(kuò)展性
    若你新建了一個(gè)郵件系統(tǒng),擁有Store的特殊子類(lèi)NewPStore,此類(lèi)采用特殊的協(xié)議NewP,并已進(jìn)行了相關(guān)設(shè)置,如在javamail.default.providers文件中設(shè)置了:
    1 protocol = NewP; type = store; class = com.sun.mail.IMAP.NewPStore;
    2
    3   這樣你就可以利用
    4
    5   Session session = Session.getDefaultInstance(props, authenticator);
    6
    7   Store store = session.getStore("NewP"); //實(shí)例化NewStore
    8
    9
    創(chuàng)建一個(gè)NewPStore型對(duì)象。
    6、總結(jié)
    Factory Method及其變異Parameterized factory method 都是極為常用的設(shè)計(jì)模式。在Javamail中還有許多地方使用了Factory Method或Parameterized Factory Method,比如類(lèi)Session中的方法getProvider、getFolder也是Parameterized Factory Method, getInstance也可以算是Parameterized Factory Method,加入收藏不過(guò)它比較特殊,它實(shí)例化Session自身。而且兩者都很容易實(shí)現(xiàn)代碼重用,進(jìn)行系統(tǒng)擴(kuò)展。
    但Factory Method模式和Parameterized factory method略有不同。對(duì)于Factory Method,有一個(gè)潛在的不利因素,那就是為了創(chuàng)建一個(gè)特殊的對(duì)象,必須有相應(yīng)于Creator的一個(gè)子類(lèi)。如上所述創(chuàng)建一個(gè)Pop3Folder對(duì)象必須要有一個(gè)Store的子類(lèi)Pop3Store, 創(chuàng)建一個(gè)IMAPFolder對(duì)象必須要有一個(gè)Store的子類(lèi)IMAPStore。而對(duì)于Parameterized factory method只需要一個(gè)具體的Creator,提供不同的參數(shù)就能創(chuàng)建不同的對(duì)象。所以可視實(shí)際情況在這兩者之中取舍。一般原則是:當(dāng)創(chuàng)建一個(gè)具體的 Product時(shí)確實(shí)需要擴(kuò)展Creator,那么就采用Factory Method,如Pop3和IMAP是兩者區(qū)別比較大的不同的郵件協(xié)議,Pop3Store和IMAPStore差異很大,創(chuàng)建Pop3Folder確實(shí)需要有一個(gè)特殊的Store擴(kuò)展--Pop3Store,對(duì)于IMAP也一樣,此時(shí)就需要采用Factory Method模式。而為了創(chuàng)建Pop3Store、IMAPStore,如還是采用Factory Method模式而分別創(chuàng)建了Session的子類(lèi)Pop3Session、IMAPSession,其意義就不是很大,完全是為了創(chuàng)建 Pop3Store而創(chuàng)建Pop3Session,Session、Pop3Session、IMAPSession三者代碼幾乎相同,可以說(shuō)是一種代碼冗余。
    總之應(yīng)該視具體情況應(yīng)用適當(dāng)?shù)脑O(shè)計(jì)模式,才能充分發(fā)揮設(shè)計(jì)模式應(yīng)有的作用。