<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    codefans

    導(dǎo)航

    <2025年7月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    統(tǒng)計(jì)

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    程序設(shè)計(jì)鏈接

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    OO隨筆(關(guān)于connection pool系列的補(bǔ)充,兼答bonmot) 選擇自 ajoo 的 Blog

    OO隨筆(關(guān)于connection pool系列的補(bǔ)充,兼答bonmot)

    說(shuō)起OO, 每個(gè)人都有每個(gè)人自己的見(jiàn)解。粗淺者如“obj.method的語(yǔ)法就是OO”;高深的則必侃“design pattern”.
    今天我也來(lái)說(shuō)說(shuō)我的一孔之見(jiàn)。

    什么是OO?
    就是面向接口編程。無(wú)論你是用vtable, 或gp的function object, 或就是C的函數(shù)指針,正交分解也好,各種pattern也罷,都是面向接口編程思想的一種實(shí)現(xiàn)。

    為什么要面向接口編程?
    為了解耦。

    什么是解耦?
    就是把程序中互相不相關(guān)或有限相關(guān)的模塊分割開(kāi)來(lái)。就象收拾屋子,你希望把不同的東西放到不同的地方。把醬油和醋倒進(jìn)不同的瓶子里去。
    這里,對(duì)完全不相關(guān)的功能,可以簡(jiǎn)單地分開(kāi)實(shí)現(xiàn)。
    但事實(shí)上,很多情況下,不同模塊之間是有互相之間的關(guān)系的。這時(shí),就需要接口。用接口準(zhǔn)確定義模塊之間的關(guān)系。解耦前,兩個(gè)模塊之間共享所有信息(這個(gè)信息包括數(shù)據(jù),也包括各自的實(shí)現(xiàn)細(xì)節(jié))。解耦后,需要共享的信息被準(zhǔn)確地定義在接口中。同時(shí),信息的流向也被確定。

    解耦的好處是什么呢?
    首先,程序變得清晰了。
    其次,不該暴露的實(shí)現(xiàn)細(xì)節(jié)被隱藏了。代碼的修改變?nèi)菀琢恕?BR>再次,結(jié)構(gòu)靈活了,通過(guò)靜態(tài)多態(tài)(function object)或動(dòng)態(tài)多態(tài)(vtable), 一個(gè)模塊可以和任意實(shí)現(xiàn)接口的模塊協(xié)作。原來(lái)類A只能與類B協(xié)作,解耦后可以和所有實(shí)現(xiàn)接口IB的類如B1, B2, ... 協(xié)作了。擴(kuò)展性大大增強(qiáng)。自然而然就代碼重用了。
    編譯依賴也沒(méi)有了。你可以專心寫(xiě)和編譯一個(gè)模塊,不用等待其它模塊的完成。
    調(diào)試容易了。只要模塊對(duì)一個(gè)接口調(diào)試成功,其它的接口也沒(méi)有問(wèn)題。于是,甚至可以用一個(gè)simple naive的實(shí)現(xiàn)該接口的dummy類來(lái)調(diào)試。(這點(diǎn),使用template的gp不適用)

    那么解耦的壞處是什么呢?
    接口的定義變得很關(guān)鍵。解耦就是隱藏一些信息,定義一些需要共享的信息。如果接口定義的不好,隱藏了不該隱藏的信息,那么對(duì)某些需要這些信息的復(fù)雜情況來(lái)說(shuō),這個(gè)解耦就失敗了。
    而如果沒(méi)有隱藏一些應(yīng)該隱藏的信息,那么不該有的耦合仍然存在。

    那么怎樣解耦,又怎樣定義接口呢?
    這是一個(gè)純粹業(yè)務(wù)邏輯的思考過(guò)程。這里,對(duì)編程語(yǔ)言的知識(shí)變得無(wú)關(guān)緊要。事實(shí)上,只要精確掌握需求,嚴(yán)密地分析需求和模塊內(nèi)部子模塊之間的需求,任何一個(gè)會(huì)邏輯思考的人都可勝任這個(gè)工作。就象歌星鄭智化一樣,雖然不識(shí)譜,但一樣寫(xiě)歌,只不過(guò)最后要懂譜的人把歌紀(jì)錄下來(lái)。
    解耦的原則很簡(jiǎn)單:精確定義需求,仔細(xì)分析需求。不要隱藏任何“需求”也許會(huì)需要的信息。不要放過(guò)任何“需求”明顯不需要的信息。
    而對(duì)需求不清楚的情況,寧可錯(cuò)放一千,不能錯(cuò)殺一個(gè)。總而言之,決不能隱藏可能需要的信息。
    不考慮重用,重用是解耦后的自然結(jié)果。不能倒因?yàn)楣?/P>

    至于對(duì)這些原則的具體的運(yùn)用在前面幾篇的connection pool的文章里已經(jīng)有所體現(xiàn)了。


    下面,我先針對(duì)bonmot對(duì)我的connection pool的例子的疑問(wèn)進(jìn)行回答。最后,再對(duì)bonmot的一個(gè)問(wèn)題給出我的解決的思路。

     

     

     

    無(wú)關(guān)緊要的問(wèn)題:
    1.ConnectionFactoryImpl也可以繼承方式實(shí)現(xiàn)ConnectionFactory

    其實(shí),我最初的實(shí)現(xiàn),的確是ConnectoinFactoryImpl implements ConnectionFactory的,
    但后來(lái),當(dāng)我overload了instance()函數(shù)之后,我發(fā)現(xiàn),這兩個(gè)函數(shù)返回的ConnectionFactory的實(shí)現(xiàn)類的代碼是不同的。于是,匿名類就誕生了。
    這里,有一點(diǎn)值得吹噓的是,對(duì)構(gòu)造函數(shù)的隱藏,使得使用ConnectionFactoryImpl的客戶代碼對(duì)我的改動(dòng)完全不敏感。這也就是我為什么一直鼓吹要隱藏構(gòu)造函數(shù)的原因。
    以下是這個(gè)類的實(shí)現(xiàn):
    public class ConnectionFactoryImpl
    {
        private ConnectionFactoryImpl(){}
        static public ConnectionFactory instance(final String driver, final String url,
         final String user, final String pwd)
        throws SQLException, ClassNotFoundException{
      final Class driverClass = Class.forName(driver);
      return new ConnectionFactory(){
       private final Class keeper = driverClass;
       public final Connection createConnection()
       throws SQLException{
        return DriverManager.getConnection(url,user,pwd);
       }
      };
        }
        static public ConnectionFactory instance(final String driver, final String url)
        throws SQLException, ClassNotFoundException{
      final Class driverClass = Class.forName(driver);
      return new ConnectionFactory(){
       private final Class keeper = driverClass;
       public final Connection createConnection()
       throws SQLException{
        return DriverManager.getConnection(url);
       }
      };
     } 
    }


    2.ConnectionFactoryImpl中
    private final Class keeper = driverClass;//似乎多余

    是啊,很多代碼里都是禿禿的Class.forName(classname)。也工作的很好。不過(guò),記得在哪篇文章里看到過(guò),在新的java language specification里,動(dòng)態(tài)加載的類有可能被垃圾回收。如果是這樣,那不麻煩啦?我好容易Class.forName()加載了driver類,好嘛!哪天jvm一高興給我回收啦!所以咱還是以防萬(wàn)一的好!

    功能的問(wèn)題
    1.ConnectionPooling是實(shí)現(xiàn)pooling的算法,其最基本的就是getConnection(),releaseConnection(Conn)
    為什么不直接在ConnectionPool定義releaseConnection()方法,而要多一個(gè)interface ConnectionHome

    首先,我的ConnectionPool接口是直接給用戶使用的。我在該文的第一章就提出,向用戶暴露releaseConnection(Connection)是不好的。你怎樣保證用戶沒(méi)有向oracle連接池中返回sql server連接?怎樣保證用戶不會(huì)把同一個(gè)連接向連接池返回兩次?已經(jīng)有Connection.close(), 用戶為什么要調(diào)用releaseConnection?

    ConnectionHome接口是PooledConnection類定義的。PooledConnection作為一個(gè)封裝在物理Connection外的與pool協(xié)同工作的類,它需要知道怎樣返還一個(gè)物理Connection. ConnectionHome接口只定義了一個(gè)方法:void releaseConnection(Connection), 就是描述這一需求的產(chǎn)物。

    2.事物總是對(duì)等的,F(xiàn)actory用于實(shí)現(xiàn)物理連接,同樣應(yīng)該負(fù)責(zé)關(guān)閉物理連接,而不應(yīng)該讓pooling算法關(guān)閉物理連接。另外,獲取與關(guān)閉connection應(yīng)該在一個(gè)接口中實(shí)現(xiàn),如果分成2個(gè)接口,就不能保證連接的實(shí)現(xiàn)一定對(duì)應(yīng)于關(guān)閉的實(shí)現(xiàn)。
    即Factory是物理層,pool是cache層,client是應(yīng)用層。

    首先,ConnectionPooling作為一個(gè)描述pooling算法的接口,它需要代表所有可能的pooling算法,所以,我們不能排除在某種pooling算法中,它會(huì)以一定的邏輯關(guān)閉物理數(shù)據(jù)庫(kù)連接。因此,pooling算法一定要可以在任何時(shí)候關(guān)閉這個(gè)連接。
    至于是調(diào)用Connection.close(), 還是放一個(gè)closeConnection方法在ConnectionFactory中,讓我們先看看一些其它的factory的實(shí)現(xiàn)。
    在COM中,IFactory的接口負(fù)責(zé)生產(chǎn)對(duì)象。但釋放對(duì)象是由IUnknown::Release()負(fù)責(zé)的。
    在Java中,很多Factory接口負(fù)責(zé)生產(chǎn)對(duì)象,但垃圾收集負(fù)責(zé)回收對(duì)象。
    為什么這些factory的機(jī)制不要求生產(chǎn)者來(lái)銷(xiāo)毀對(duì)象呢?
    其原因在于類型安全!
    舉個(gè)例子:
    class Factory{
       public Object getObject(){
         if(...)return new ClassA();
         else return new ClassB();
       }
       public void release(Object obj){
         if(obj 是ClassA){
             ((ClassA)obj).closeA();
         }
         else{
             ((ClassB)obj).closeB();
         }
         /*丑啊!*/
       }
    }
    在這樣一個(gè)工廠里,getObject方法知道生產(chǎn)的對(duì)象的真正類型。但在返回之后,該對(duì)象的真正類型就被丟失了。
    這樣,如果你再把對(duì)象送還給工廠,說(shuō):“嘿!這是從你們廠出的,現(xiàn)在我不用了,還給你。”對(duì)工廠來(lái)說(shuō),它需要:
    1, 確認(rèn)這個(gè)對(duì)象真是出自本廠。(這可不那么容易)
    2, 確認(rèn)這個(gè)對(duì)象是怎么造出來(lái)的。以便找出相應(yīng)的銷(xiāo)毀機(jī)制(也不容易)
    我們?yōu)槭裁床话裷eleaseConnection對(duì)用戶公開(kāi)?也是因?yàn)榭紤]到用戶可能會(huì)錯(cuò)誤返還非本廠生產(chǎn)的東西。
    其實(shí),當(dāng)對(duì)象出廠之后,只有對(duì)象自己才知道怎樣銷(xiāo)毀自己。其它任何對(duì)象,包括生產(chǎn)者,都無(wú)能為力。


    4.可靠性不夠。表現(xiàn)在:
    a.pool的可靠性應(yīng)該與server的可靠性無(wú)關(guān),即database server或socket server可能由于某些原因重新啟動(dòng),但pool不應(yīng)該也要重新啟動(dòng)(比如一個(gè)pool存有不同server的connection),否則就跑出錯(cuò)誤。所以,pool因該檢查物理connection的連接狀態(tài)

    怎么說(shuō)呢?這屬于ConnectionPool這個(gè)接口的語(yǔ)義。我們是否想讓我們的pool即使數(shù)據(jù)庫(kù)server崩潰了也能工作呢?
    首先,這樣做是否有意義呢?如果數(shù)據(jù)庫(kù)server崩潰了,我們的Connection pool怎么補(bǔ)救呢?
    其次,就算這樣是有意義的,它也是ConnectionPooling的邏輯。完全可以交給一個(gè)對(duì)此負(fù)責(zé)的ConnectionPooling處理。

    b.pooled Connection可能由于一個(gè)client忘記關(guān)閉,而導(dǎo)致整個(gè)pool阻塞。所以,應(yīng)該對(duì)pooled Connection進(jìn)行監(jiān)控,對(duì)于超時(shí)的或其他invaild狀態(tài)的pooled connection強(qiáng)制回收。

    這個(gè)問(wèn)題提的好!起初,我覺(jué)得這也只是另一個(gè)ConnectionPooling的邏輯。可以交給一個(gè)監(jiān)測(cè)已分配的連接使用情況的ConnectionPooling實(shí)現(xiàn)來(lái)處理。但仔細(xì)一想。這樣做是不好的。

    首先,監(jiān)視連接的使用一定會(huì)需要在連接對(duì)象上記錄一些狀態(tài),象連接分配的時(shí)間,最近一次客戶使用該連接的時(shí)間等等。而ConnectionPooling的語(yǔ)義是返回pool里的物理連接,而由ConnectionPooling2Pool類來(lái)做封裝。這樣,ConnectionPooling的實(shí)現(xiàn)就很難紀(jì)錄必要的信息。當(dāng)然,ConnectionPooling也可以在返回物理連接前先做一個(gè)wrapper, 把信息紀(jì)錄在這個(gè)wrapper里。可是,這樣一來(lái),類型安全就得不到保障。在使用該wrapper時(shí),就要進(jìn)行downcast.

    其次,監(jiān)視已分配連接和管理空閑連接之間到底有多大耦合呢?能否對(duì)它們解耦呢?經(jīng)過(guò)分析,我感覺(jué),答案是:不能。監(jiān)視已分配連接的算法理論上有可能需要知道空閑連接的一些信息,而反之也是一樣。而且,更討厭的是,它們之間所需要的信息量無(wú)法估計(jì),也就是說(shuō),對(duì)一些特定的算法,它們可能是完全的緊耦合。如果按這樣分析,這種ConnectionPool可能還得要求實(shí)現(xiàn)者直接實(shí)現(xiàn)ConnectionPool, 就象我們第三章里使用的方法,只能偶爾使用一些utility類,象PooledConnection之類。
    不過(guò),雖然我們不能完全把監(jiān)視算法和分配算法分開(kāi)。但事實(shí)上很多監(jiān)視算法,分配算法確實(shí)是互不相關(guān)的。我們也許可以寫(xiě)一個(gè)框架,簡(jiǎn)化對(duì)這些互不相關(guān)的算法的實(shí)現(xiàn)。雖然對(duì)完全緊耦合的情況我們無(wú)能為力,但對(duì)多數(shù)普通的情況,我們還是可以有些作為的。而且,這樣一個(gè)框架并不影響對(duì)復(fù)雜的緊耦合情況的特殊實(shí)現(xiàn)。
    這個(gè)框架,當(dāng)然應(yīng)該和我們現(xiàn)有的框架協(xié)同工作。具體的實(shí)現(xiàn)思路,我將在后面給出。

    c.ConnectionPoolingImpl
        public final synchronized void clear(){
          closeAll();
          freeConn.removeAllElements();
        }//沒(méi)有transaction保證,有可能引起數(shù)據(jù)不一致,資源(connection)泄漏(connection沒(méi)關(guān)閉,pool卻拿掉了)
        可以關(guān)閉一個(gè)connection,去掉一個(gè)pool對(duì)象

    這里不需要transaction保證的。我們先關(guān)閉所有連接,然后再清連接池,怎么可能“connection沒(méi)關(guān)閉,pool卻拿掉了”呢?

    擴(kuò)展的問(wèn)題
    1.ConnectionPool是否定義成一個(gè)結(jié)構(gòu)interface更好,而讓pooling實(shí)現(xiàn)pooling算法。
    pool可定義成Vector,Tree,...,負(fù)責(zé)存儲(chǔ)遍歷,而pooling負(fù)責(zé)check in,check out.

    數(shù)據(jù)結(jié)構(gòu)和算法永遠(yuǎn)是緊耦合的。實(shí)際上,算法決定數(shù)據(jù)結(jié)構(gòu),不可能實(shí)現(xiàn)定義一個(gè)數(shù)據(jù)結(jié)構(gòu),然后強(qiáng)迫所有算法使用。即使是Collection, Iterator之類較抽象的結(jié)構(gòu)也不行。

    2.可能有大型的pool,比如字庫(kù),因此有檢索問(wèn)題

    這就是ConnectionPooling的實(shí)現(xiàn)者要?jiǎng)拥哪X筋了。我們的框架只定義語(yǔ)義和責(zé)任分工,并不牽扯這樣的實(shí)現(xiàn)細(xì)節(jié)。

    2.更復(fù)雜的是可能每個(gè)connection上有多個(gè)引用,pooling要負(fù)責(zé)給client引用最少的那個(gè)connection.

    這還是一個(gè)實(shí)現(xiàn)的細(xì)節(jié)。不過(guò)我想不出有什么理由我們會(huì)要不同客戶共享同一個(gè)連接。這是不安全的,不是嗎?

    3.可能同一個(gè)pool存儲(chǔ)不同類型的對(duì)象,對(duì)不同對(duì)象的處理是否可用visitor模式。

    還是ConnectionPool的實(shí)現(xiàn)者的事。

     


    相關(guān)文章
    對(duì)該文的評(píng)論
    ajoo ( 2002-08-07)
    myan, 我想我可能是沒(méi)有明白你的意思。那個(gè)關(guān)于hdc的東西,就當(dāng)我沒(méi)說(shuō)吧。

    至于pattern與否。我總覺(jué)得pattern看看可以。用來(lái)和別人交流也不錯(cuò)。
    但真正做東西時(shí),往往是做完了之后才reverse-engineer, 發(fā)現(xiàn):“啊,我這里用的是bridge嘛,那里用的是state..."
    對(duì)于你的gui框架。我想,我會(huì)本著“分析需求;用接口定義需求;解耦”的原則來(lái)設(shè)計(jì)。并且象我上一貼提到的剝皮般地
    進(jìn)行逐層細(xì)分。這樣,即使你最后發(fā)現(xiàn)某一部分不合適,修改也會(huì)被局限在最小的范圍內(nèi)。
    舉個(gè)例子,它就象通訊協(xié)議里的層:
    定義了網(wǎng)絡(luò)層,下面又可以定義鏈路層,物理層。但對(duì)于網(wǎng)絡(luò)層的用戶,其它兩層都是透明的,并不是必然的,或強(qiáng)迫的。如果實(shí)現(xiàn)者覺(jué)得好,完全可以繞過(guò)鏈路層,或再加幾層。無(wú)論如何更改,不影響網(wǎng)絡(luò)層的用戶。而遞歸地,對(duì)于鏈路層的用戶,物理層的實(shí)現(xiàn)又是透明的。

    當(dāng)然,面向接口的OO, 并不適合對(duì)performance敏感到一兩個(gè)函數(shù)調(diào)用開(kāi)銷(xiāo)都要計(jì)較的應(yīng)用,aggregate, interface的使用,總會(huì)引入一定的開(kāi)銷(xiāo)。

    bonmot ( 2002-08-05)
    myan,
    個(gè)人覺(jué)得,設(shè)計(jì)時(shí)結(jié)構(gòu)性質(zhì)的pattern或不是pattern的框架已經(jīng)成形,refactor時(shí)某些實(shí)現(xiàn)的pattern會(huì)自然而然逐步顯現(xiàn)。

    ajoo,
    如果factory維持對(duì)產(chǎn)品的引用,肯定是可以回收的,只是這樣會(huì)增加factory的復(fù)雜度,是否好可以商榷。
    ar7_top ( 2002-08-04)
    學(xué)習(xí)
    waveless ( 2002-08-03)
    ajoo關(guān)于DC的那段我沒(méi)看懂,myan的意思應(yīng)該是在用到j(luò)peg2dib轉(zhuǎn)換
    的某個(gè)函數(shù)里面無(wú)法得到和窗口相關(guān)的HDC了。這里的hdc應(yīng)該是個(gè)參
    數(shù)。HdbJpeg2Dib里的HDC是那兒來(lái)的?

    當(dāng)然象jpeg2dib這樣的過(guò)程中理論上是不應(yīng)該需要HDC做參數(shù)的,但
    是Windows中和DIB有關(guān)的很多函數(shù)都需要HDC。其實(shí)只是為了取得一
    些設(shè)置象調(diào)色板什么的,用GetDC(NULL)取個(gè)設(shè)備DC給它應(yīng)該就可以。
    不一定非要是某一個(gè)窗口的DC。但是這需要先看懂它的代碼,并對(duì)
    Windows中有關(guān)DIB的函數(shù)很熟悉。這樣就失去用現(xiàn)成庫(kù)的意義了。
    ajoo ( 2002-08-03)
    myan:
    還不是很明白。如果Jpeg2Dib是一個(gè)接口:
    interface Jpeg2Dib{
       virtual Dib* convert(Jpeg* jpeg)=0;
    };
    難道你不能這樣實(shí)現(xiàn)?
    class HdbJpeg2Dib:public Jpeg2Dib{
       public:
       Dib* convert(Jpeg* jpeg){
          return ::convert_func(hdc, jpeg);
       }
       private:
       const HDC hdc;
    };

    bonmot:
    我覺(jué)得你沒(méi)有很明白面向接口的意思。為什么不要求保證ConnectionPool實(shí)現(xiàn)中一定引用ConnectionPooling接口呢?因?yàn)檫@樣做是不好的。
    面向接口的原則是:誰(shuí)需要,就有誰(shuí)定義。提供功能的類可以不定義接口。但需要功能的模塊一定要定義所需要的接口。
    我們的ConnectionPool是pool的用戶需要的。對(duì)于一個(gè)ConnectionPool的用戶來(lái)說(shuō),他并不關(guān)心你是用什么巧妙的方法實(shí)現(xiàn)的這個(gè)ConnectionPool, 只要它能完成所定義的操作,對(duì)用戶來(lái)說(shuō)就可以。誰(shuí)管你是直接實(shí)現(xiàn)的還是用的什么pattern? ConnectionPooling相對(duì)于ConnectionPool的用戶來(lái)說(shuō),只是實(shí)現(xiàn)細(xì)節(jié)。屬于解耦要隱藏的無(wú)關(guān)信息。
    所以沒(méi)有理由要把ConnectionPooling的細(xì)節(jié)公之于眾。

    也許你要說(shuō):應(yīng)該強(qiáng)迫程序員在實(shí)現(xiàn)ConnectionPool的時(shí)候使用ConnectionPooling. 我覺(jué)得這種強(qiáng)迫是不應(yīng)該的。無(wú)論你的實(shí)現(xiàn)方法多么巧妙,你永遠(yuǎn)不應(yīng)該把它強(qiáng)加于人。
    而且,現(xiàn)實(shí)世界的復(fù)雜性永遠(yuǎn)是超過(guò)我們的想象的。無(wú)論你多么激動(dòng)于自己天才的實(shí)現(xiàn)方法,都不要以為它可以解決所有問(wèn)題。就象你提出的監(jiān)測(cè)已分配的連接的使用,它就完全可能和ConnectionPool的實(shí)現(xiàn)緊耦合,而使得我們的bridge pattern (僅僅實(shí)現(xiàn)ConnectionPooling)無(wú)法有效實(shí)現(xiàn)需求。
    另外,即使我們的ConnectionPooling的方法真能解決所有ConnectionPool實(shí)現(xiàn)的需求,我們就可以強(qiáng)迫所有實(shí)現(xiàn)都用它嗎?如果忽然有人給了我們一個(gè)已經(jīng)實(shí)現(xiàn)好的connection pool, 它是五年前設(shè)計(jì)的,完全沒(méi)有用我們的ConnectionPooling的方法,難道我們就不能使用它了嗎?為什么不能簡(jiǎn)單地用一個(gè)adapter來(lái)用它呢?

    其實(shí),我頂煩某些巨大的framework, 你要不就用它,享受它的好處,也忍受它的局限。要不就只能干脆拋開(kāi)它。象MFC就是這樣。
    一個(gè)真正的面向接口的設(shè)計(jì)應(yīng)該開(kāi)放的,我的想象應(yīng)該是這樣:
    首先,假設(shè)需要實(shí)現(xiàn)的系統(tǒng)的功能被定義在一系列接口中。ok, 這些接口就是需求,無(wú)論你怎樣實(shí)現(xiàn)。
    現(xiàn)在,我們要實(shí)現(xiàn)這些接口。在實(shí)現(xiàn)過(guò)程中,我們發(fā)現(xiàn)系統(tǒng)可以被拆成幾個(gè)獨(dú)立的模塊,(這里的“可以”,可以是我們對(duì)需求的分析,認(rèn)為這幾個(gè)模塊可以自然被解耦,也可能是我們發(fā)現(xiàn),雖然該系統(tǒng)理論上是個(gè)緊耦合,但對(duì)一些特定的場(chǎng)合,還是可以做一些分解以簡(jiǎn)化實(shí)現(xiàn))。這樣,幾套子需求被定義。系統(tǒng)被拆成幾個(gè)小系統(tǒng),幾套子接口,以及組合小系統(tǒng)為大系統(tǒng)的邏輯。
    這里,對(duì)頂層接口來(lái)說(shuō),這些子系統(tǒng),子接口,都不是必須的。它們只是“限于我們有限的知識(shí)和經(jīng)驗(yàn)所使用的一種我們覺(jué)得好的實(shí)現(xiàn)方法”。所以,如果以后有我們的設(shè)計(jì)所沒(méi)有預(yù)料到的情況,至少我們還可以直接繞過(guò)這層設(shè)計(jì),不會(huì)影響頂層的接口。
    好,同樣的分析,分解,遞歸地在實(shí)現(xiàn)每個(gè)子系統(tǒng)時(shí)使用。直到設(shè)計(jì)者認(rèn)為已分解的足夠細(xì),或留到以后refactor時(shí)再說(shuō)。
    在這一層一層的分解過(guò)程中,每一層對(duì)其上一層來(lái)說(shuō)都不是必須的,并且是透明的。這樣,如果后來(lái)的實(shí)現(xiàn)者發(fā)現(xiàn)某一個(gè)子模塊設(shè)計(jì)得不能完全符合需要,都完全可以推倒重來(lái)。
    在這樣的一個(gè)開(kāi)放式的設(shè)計(jì)中,沒(méi)有什么是強(qiáng)迫的。從最頂層的實(shí)現(xiàn),到底層的某個(gè)小子模塊的實(shí)現(xiàn),都不是神圣不可侵犯的。
    當(dāng)然,系統(tǒng)設(shè)計(jì)的目標(biāo)是要盡量避免將來(lái)對(duì)相對(duì)頂層的子系統(tǒng)設(shè)計(jì)更換的可能性。因?yàn)椋礁鼡Q頂層,代價(jià)越大,除非,那只是一個(gè)用于demo或測(cè)試的dummy實(shí)現(xiàn), 或一個(gè)其它legacy system的adapter。

    這里,設(shè)計(jì)者應(yīng)是謙虛的,不是說(shuō):“我就是這樣設(shè)計(jì)的,想要靈活性?呵呵,我都預(yù)想到了,這里,這里,這里,都是我預(yù)留的供你cusomize的地方。什么?不夠?不可能!”
    而是說(shuō):“我的設(shè)計(jì)不一定就是最好的,如果你認(rèn)為有更好的設(shè)計(jì)實(shí)現(xiàn)方法,或它不能滿足你的需要,你可以輕易地使用你自己的方法。我的任何一層你都可以替換成你的實(shí)現(xiàn)。”

    另外,用factory來(lái)釋放對(duì)象確實(shí)是不可行的。用template?template依賴于靜態(tài)類型。而factory方法的返回類型只能是一個(gè)。

    elm:
    我覺(jué)得你所描述的接口系統(tǒng)就象我說(shuō)的mfc式的封閉式的系統(tǒng)。繁文縟節(jié)都規(guī)定好了,只能使用,或在實(shí)現(xiàn)預(yù)留好的地方做些修改。
    比如說(shuō):總經(jīng)理告訴項(xiàng)目經(jīng)理要上一個(gè)項(xiàng)目。項(xiàng)目經(jīng)理必須先開(kāi)動(dòng)員會(huì),再做項(xiàng)目報(bào)告,再做需求分析。。。。。。一系列的過(guò)程都定死了。
    而一個(gè)開(kāi)放式的系統(tǒng)是:總經(jīng)理告訴項(xiàng)目經(jīng)理要上一個(gè)項(xiàng)目,項(xiàng)目經(jīng)理只負(fù)責(zé)最終實(shí)現(xiàn)這個(gè)項(xiàng)目,給出所有需要的deliverables.
    對(duì)項(xiàng)目經(jīng)理來(lái)說(shuō),它可以是用上面描述的方法來(lái)組織項(xiàng)目。但那并不是公司要求的。如果需要,完全可以換個(gè)項(xiàng)目經(jīng)理,引入一個(gè)新的方法。

    myan:
    我倒沒(méi)感覺(jué)你的那個(gè)gui系統(tǒng)就一定是composition或其它的任何一種pattern. :)
    我覺(jué)得,用上面說(shuō)的那種撥皮式的方法,即使你最后要修改實(shí)現(xiàn),應(yīng)該也不是個(gè)很大的工程。為什么上來(lái)就直奔pattern而去呢?
     

    posted on 2005-11-22 11:52 春雷的博客 閱讀(284) 評(píng)論(0)  編輯  收藏


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲另类春色校园小说| 亚洲AV成人无码久久精品老人| 亚洲春色在线观看| 亚洲视频在线观看免费| 亚洲男同帅GAY片在线观看| 久青草视频97国内免费影视| 国产亚洲日韩一区二区三区| 一区二区在线免费视频| 在线观看国产区亚洲一区成人 | 日韩内射激情视频在线播放免费| 国产亚洲美日韩AV中文字幕无码成人 | 18禁亚洲深夜福利人口| 国产成人青青热久免费精品| 看一级毛片免费观看视频| 亚洲高清偷拍一区二区三区| 午夜成人无码福利免费视频| 亚洲精品久久久www| 日韩精品无码免费专区网站| 亚洲一本综合久久| h片在线免费观看| 亚洲精品无码av片| 亚洲偷自拍拍综合网| 国产精品免费观看调教网| 亚洲成AV人片久久| 性做久久久久免费看| 久久久久女教师免费一区| 亚洲视频在线视频| 毛片免费视频在线观看| 全部在线播放免费毛片| 亚洲动漫精品无码av天堂| 无人在线直播免费观看| 在线精品自拍亚洲第一区| 久久精品国产亚洲网站| 无人在线观看完整免费版视频| 黄色毛片免费观看| 久久久久亚洲AV无码观看 | 日韩av无码免费播放| 亚洲一级高清在线中文字幕| 亚洲av无码天堂一区二区三区| 国产精品免费无遮挡无码永久视频| 在线亚洲午夜片AV大片|