Разработка драйвера базы данных Java - PullRequest
6 голосов
/ 20 января 2010

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

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

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

Какая модель для этого подходит?

Ответы [ 3 ]

6 голосов
/ 20 января 2010

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

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

Этот псевдо-код имеет синтаксис, аналогичный 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()

К сожалению, это выглядит немного сложным.

ООП во многом основано на полиморфизме.

Итак, в Dao вы позволяете подклассу получать данные из любого места и просто вызываете ихdao.fetch ().

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

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

if isBroken and itDoesntWork() and if ImAlive()

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

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

1 голос
/ 20 января 2010

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

0 голосов
/ 20 января 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...