簡體   English   中英

Java數據庫驅動程序設計

[英]Java database driver design

我有這個問題,我需要設計一個Java包,用於:

  • 從不同的數據源獲取數據。 例如,A類將從Oracle數據庫中檢索客戶數據,而B類將從Web服務數據源(通過SOAP )檢索相同的信息。
  • 結果將需要結合,組合規則非常復雜,所以理想情況下我應該從這個包的用戶(其他開發人員)中隱藏它。
  • 當一個數據源出現故障時,我仍然需要從其他數據源返回結果。 但是,我還需要讓調用者知道其中一個數據源無法響應。

現在我正在通過在A類和B類中包含一個布爾值來指示是否存在錯誤,以及另一個用於存儲實際錯誤消息的對象來實現。 調用者在調用之后必須檢查此布爾值以查看是否發生了錯誤。

這有什么好的設計模型?

答案非常寬泛,所以我建議你使用:

這個偽代碼具有與UMLPython類似的語法:

// The data implements one interface
Data {interface}

// And you implement it with DatabaseData
DbData -> Data
   ...

// Or WebServiceData
WsData -> Data
   ...

// -- DAO part
Dao {interface}
   + fetch(): Data[]

// From database
DatabaseDao -> Dao
    - data: Data[0..*]
    // Query database and create dbData from rows...
    + fetch(): Data[]
        self.status = "Not ok"
        self.status = connectToDb()
        if( self.status == ok ,
            performQuery()
            forEach( row in resultSet,
                data.add( DbData.new( resultSet.next() ) )
            )
            disconnect()
        )
    ...

// From web service
WebServiceDao -> Dao
    - data: Data[0..*]
    // Execute remote method and create wsData from some strange object
    + fetch(): Data[]
        remoteObject: SoapObject = SoapObject()
        remoteObject.connect()
        if (remoteObject.connected?(),
            differentData: StrangeObject = remoteObject.getRemoteData()
            forEach( object in differentData ,
                self.data.add( WsData.new( fromElement ))
            )
        ).else(
           self.status = "Disconnected"
        )
    ....
// -- State part
// Abstract the way the data is going to be retrieved
// either from two sources or from a single one.
FetcheState { abstract }

    - context: Service
    - dao: Dao // Used for a single source

    + doFetch(): Data[] { abstract }

    + setContext( context: Service )
        self.context = context
    + setSingleSource( dao: Dao)
        self.dao = dao

// Fetches only from one DAO, and it doesn't quite merge anything
// because there is only one source after all.
OneSourceState -> FetcheState
   // Use the single DAO and fetch
   + doFetch(): Data[]
       data: Data[] =  self.dao.doFetch()
       // It doesn't hurt to call "context's" merger anyway.
       context.merger.merge( data, null )

// Two sources, are more complex, fetches both DAOs, and validates error.
// If one source had an error, it changes the "state" of the application (context),
// so it can fetch from single source next time.
TwoSourcesState -> FetcheState
    - db: Dao = DatabaseDao.new()
    - ws: Dao = WebServiceDao.new()

    + doFetch(): Data[]
        dbData: Data[] =  db.doFetch()
        wsData: Data[] =  ws.doFetch()

        if( ws.hadError() or db.hadError(),
            // Changes the context's state
            context.fetcher = OneSourceState.new()
            context.merger = OneKindMergeStrategy.new()
            context.fetcher.setContext( self.context )
            // Find out which one was broken
            if( ws.hadError(),
                context.fetcher.setSingleSource( db )
            )
            if( db.hadError(),
                context.fetcher.setSingleSource( ws )
            )
        )
        // Since we have the data already let's 
        // merge it with the "context's" merger.
        return context.merger.merge( dbData, wsData)

// -- Strategy part --
// Encapsulate algoritm to merge data
Strategy{ interface }
    + merge( a: Data[], with : Data[]  )

// One kind doesn't merge too much, just "cast" one array
// because there is only one source after all.
OneKindMergeStrategy -> Strategy
    + merge( a: Data[], b: Data[]  )
         mergedData: Data[]
         forEach( item, in( a ),
            mergedData = Data.new( item ) // Take values from wsData or dbData
         )
         return mergedData

// Two kinds merge, encapsulate the complex algorithm to
// merge data from two sources.
TwoKindsMergeStrategy -> Strategy
    + merge( a: Data[], with: Data[] ): Data[]
        forEach( item, in( a ),
            mergedData: Data[]
            forEach( other, in(with ),
                 WsData wsData = WsData.cast( item )
                 DbData dbData = DbData.cast( other )
                 // Add strange and complex logic here.
                 newItem = Data.new()
                 if( wsData.name == dbData.column.name and etc. etc ,
                    newItem.name = wsData+dbData...e tc. etc
                    ...
                    mergedData.add( newItem )
                 )
            )
        )
        return mergedData

// Finally, the service where the actual fetch is being performed.
Service  { facade }

    - merger: Strategy
    - fetcher: FetcheState

    // Initialise the object with the default "strategy" and the default "state".
    + init()
        self.fetcher  = TwoSourcesState()
        self.merger = TwoKindsMergeStrategy()
        fetcher.setContext( self )

    // Nahh, just let the state do its work.
    + doFetch(): Data[]
        // Fetch using the current application state
        return fetcher.doFetch()

客戶用法:

     service: Service = Service.new()
     service.init()
     data: Data[] = service.doFetch()

不幸的是,它看起來有點復雜。

OOP基於多態性。

所以在Dao ,你讓子類從任何地方獲取數據,你只需稱它為dao.fetch()。

Strategy中,子類執行一個算法或另一個算法(以避免有很多奇怪的, if是, else的, switch等)。

State同樣的事情發生。 而不是像:

if isBroken and itDoesntWork() and if ImAlive()

您只需說,“嘿,這將是代碼一。有兩個連接,這是只有一個。”。

最后,門面對客戶說:“別擔心,我會處理這個問題。”

您需要編寫解決方案,還是需要解決方案? 有很多免費的Java軟件可以完成這些工作 - 為什么要重新發明輪子。 看到:

我建議一個Facade代表整個對象(客戶數據)和一個工廠,它通過從每個數據源檢索並將它們傳遞給Facade(在構造函數中或作為構建器,根據有多少)來創建該對象有)。 具有特定數據源的單個類將具有一個方法(在公共接口或基類上),以指示檢索數據時是否存在錯誤。 Facade(或代表)將負責組合數據。

然后Facade將有一個方法,它將返回某種類型的集合,指示對象所代表的數據源,或哪些數據源失敗 - 取決於客戶端需要知道的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM