2010-01-20 20 views
6

tengo este problema donde tengo que diseñar un paquete de Java que se utiliza para:Java controlador de base de datos de diseño

  • datos obtenidos de diferentes fuentes de datos. Por ejemplo, la Clase A recuperará los datos del cliente de una base de datos Oracle, mientras que la Clase B recuperará la misma información de una fuente de datos del servicio web (a través del SOAP).
  • Los resultados deberán combinarse, la regla de combinación es bastante compleja, por lo que idealmente debería ocultar esto a los usuarios (otros desarrolladores) de este paquete.
  • Cuando fallan las fuentes de datos, necesito devolver el resultado de otras fuentes de datos. Sin embargo, también debo informarle a la persona que llama que una de las fuentes de datos no respondió.

Ahora lo hago teniendo un valor booleano dentro de la Clase A y Clase B que indica si hay un error y otro objeto para almacenar el mensaje de error real. La persona que llama deberá verificar este valor booleano después de realizar una llamada para ver si se ha producido un error.

¿Qué es un buen modelo de diseño para esto?

+1

Me encanta cuando alguien hace la misma pregunta exactamente de la que estoy desconcertando en este momento. Gracias. – Martin

Respuesta

6

La respuesta sería muy amplio, por lo que podría sugerir que use el:

  • El Data Access Object (DAO) design pattern abstraer la fuente de los datos (base de datos o servicio web)
  • El strategy pattern para abstraer el algoritmo de que los datos se combinan (cuando ambas fuentes están disponibles y una solo hay una)
  • Y finalmente el state design pattern para cambiar la forma en que funciona su aplicación, dependiendo de la fuente que esté disponible.
  • Todo esto envuelto (¿por qué no?) En un buen facade.

Esta pseudo código tiene una sintaxis similar a la UML y 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() 

uso del cliente:

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

Desafortunadamente, parece un poco complejo.

OOP se basa mucho en el polimorfismo.

Por lo tanto, en Dao, permite que la subclase busque datos desde cualquier lugar y simplemente lo llama dao.fetch().

En Strategy la misma, la subclase realiza un algoritmo o el otro (para evitar tener una gran cantidad de extrañas if 's, else' S, switch 'S, etc.).

Con State sucede lo mismo. En lugar de ir como:

if isBroken and itDoesntWork() and if ImAlive() 

etc, etc que acaba de decir, "Hey, este será el código de una Hay dos conexiones y esto es cuando sólo hay una..".

Finalmente, la fachada le dice al cliente "No se preocupe, yo manejaré esto".

+0

Gran respuesta incluso antes del pseudo código. – Martin

+0

+1 para el patrón de estado. ¿Por qué empezaste todo de nuevo la 3ª vez? –

+0

@Vinegar: gracias. Acerca de la 3ra. Respondí en otro hilo – OscarRyz

0

que sugeriría una fachada que representaría el objeto en su conjunto (los datos de los clientes) y una fábrica que crea ese objeto recuperando de cada fuente de datos y pasándolos a la Fachada (en el constructor o como un constructor, dependiendo de cuántos hay). La clase individual con la fuente de datos específica tendría un método (en una interfaz común o clase base) para indicar si hubo un error al recuperar los datos. La Fachada (o un delegado) sería responsable de combinar los datos.

Luego, la Fachada tendría un método que devolvería una colección de algún tipo que indicara qué fuentes de datos representaba el objeto, o cuáles fallaron, dependiendo de lo que el cliente necesita saber.

Cuestiones relacionadas