Java数据库驱动程序设计

时间:2010-01-20 02:54:15

标签: java database

我有这个问题需要设计一个用于以下的Java包:

  • 从不同的数据源获取数据。例如,A类将从Oracle数据库中检索客户数据,而B类将从Web服务数据源检索相同的信息(通过SOAP)。
  • 结果需要合并,组合规则非常复杂,所以理想情况下我应该将此隐藏在此软件包的用户(其他开发人员)中。
  • 当一个数据源出现故障时,我仍然需要从其他数据源返回结果。但是,我还需要让调用者知道其中一个数据源无法响应。

现在,我正在通过在A类和B类中指定是否存在错误的布尔值以及用于存储实际错误消息的另一个对象来实现此目的。调用者在调用之后必须检查此布尔值以查看是否发生了错误。

对此有什么好的设计模型?

3 个答案:

答案 0 :(得分:6)

答案非常宽泛,所以我建议您使用:

此伪代码的语法与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相同的情况下,子类执行一种算法或另一种算法(以避免有很多奇怪的ifelseswitch' s等。)。

State同样的事情发生了。而不是像:

if isBroken and itDoesntWork() and if ImAlive()
等等,你只是说,“嘿,这将是代码一。有两个连接,这是只有一个。”。

最后,门面对客户说:“别担心,我会处理这个。”。

答案 1 :(得分:1)

您需要编写解决方案,还是需要解决方案?有很多免费的Java软件可以完成这些工作 - 为什么要重新发明轮子。参见:

答案 2 :(得分:0)

我建议一个Facade代表整个对象(客户数据)和一个工厂,它通过从每个数据源检索并将它们传递给Facade(在构造函数中或作为构建器,依赖于有多少)。具有特定数据源的单个类将具有一个方法(在公共接口或基类上),以指示检索数据时是否存在错误。 Facade(或代表)将负责组合数据。

然后Facade将有一个方法可以返回某种类型的集合,指示对象所代表的数据源,或哪些数据源失败 - 取决于客户端需要知道的内容。