Дизайн драйвера базы данных Java

У меня есть эта проблема, где я должен разработать пакет Java, который используется для:

  • Получение данных из различных источников данных. Например, Класс A получит данные о клиентах от базы данных Oracle, в то время как Класс B получит ту же информацию от источника данных веб-сервиса (через SOAP).
  • Результаты должны будут быть объединены, правило для комбинации довольно сложно, так идеально я должен скрыть это от пользователей (другие разработчики) этого пакета.
  • Когда сбои источников данных, я должен все еще возвратить результат других источников данных. Однако я также должен позволить вызывающей стороне знать, что одному из источников данных не удалось ответить.

Прямо сейчас я делаю его при наличии булева значения в Классе A и Классе B, указывающем, существует ли ошибка и другой объект для хранения фактического сообщения об ошибке. Вызывающая сторона должна будет проверить это булево значение после звонка, чтобы видеть, произошла ли ошибка.

Что такое хорошая модель дизайна для этого?

6
задан Peter Mortensen 7 October 2013 в 18:59
поделиться

3 ответа

Ответ был бы очень широким, поэтому я бы предложил вам использовать объект доступа:

  • объекта доступа к данным [DAO) , чтобы аннотация источника данных (база данных или Webservice)
  • Узор структура для абстрактного алгоритма, посредством которого имеются данные (когда доступны как источники, и один, есть только один)
  • и, наконец, шаблон конструкции состояния Измените способ работы вашего приложения в зависимости от того, какой источник доступен.
  • Все это завернуто (почему нет) в приятном фасада .

Этот код PSuedo имеет аналогичный синтаксис как UML и Python :

// 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 ().

В стратегия то же самое, подкласс выполняет один алгоритм или другой (чтобы избежать много странного , если , else , Переключатель и т. Д.).

С состоянием то же самое происходит. Вместо того, чтобы идти как:

if isBroken and itDoesntWork() and if ImAlive()

и т. Д., И т. Д. Вы просто говорите: «Эй, это будет код один. Есть два соединения, и это, когда есть только один».

Наконец, фасад говорит клиенту «Не волнуйся, я справимся с этим».

6
ответ дан 17 December 2019 в 00:09
поделиться

Вам необходимо написать решение или Вам нужно решение? Есть много бесплатного программного обеспечения Java, которое делает эти вещи - зачем восстанавливать колесо. См.:

1
ответ дан 17 December 2019 в 00:09
поделиться

Я бы предложил бы фасад, который будет представлять объект в целом (данные клиента) и фабрику, который создает этот объект, извлекивая из каждого источника данных и передаю их на фасаду (в конструкторе или в качестве строителя, в зависимости от На сколько есть). Отдельный класс с конкретным источником данных будет иметь метод (на общий интерфейс или базовый класс), чтобы указать, что произошла ошибка, извлекая данные. Фасад (или делегат) будет нести ответственность за объединение данных.

Тогда фасад будет иметь метод, который вернет сборку своего рода, указывающую, какие источники данных представлен объект, или какие из них не удалось - в зависимости от того, что клиент должен знать.

0
ответ дан 17 December 2019 в 00:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: