Java数据库驱动程序设计

Joh*_*ohn 6 java database

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

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

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

这有什么好的设计模型?

Osc*_*Ryz 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()
Run Code Online (Sandbox Code Playgroud)

客户用法:

     service: Service = Service.new()
     service.init()
     data: Data[] = service.doFetch()
Run Code Online (Sandbox Code Playgroud)

不幸的是,它看起来有点复杂.

OOP基于多态性.

因此Dao,您可以让子类从任何地方获取数据,然后将其称为dao.fetch().

Strategy相同的,子类执行一个算法或其他(以避免具有很多奇怪的if年代,else年代,switch年代,等等).

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

if isBroken and itDoesntWork() and if ImAlive()
Run Code Online (Sandbox Code Playgroud)

您只需说,"嘿,这将是代码一.有两个连接,这是只有一个.".

最后,门面对客户说:"别担心,我会处理这个问题."