2010-01-20 17 views
6

ho questo problema in cui ho bisogno di progettare un pacchetto Java che viene utilizzato per:Java driver del database di progettazione

  • Ottenere i dati provenienti da diverse fonti di dati. Ad esempio, la Classe A recupererà i dati dei clienti da un database Oracle, mentre la Classe B recupererà le stesse informazioni da un'origine dati del servizio Web (tramite SOAP).
  • I risultati dovranno essere combinati, la regola per la combinazione è piuttosto complessa, quindi idealmente dovrei nasconderlo agli utenti (altri sviluppatori) di questo pacchetto.
  • Quando una fonte di dati non funziona, devo comunque restituire il risultato da altre origini dati. Tuttavia, devo anche far sapere al chiamante che una delle fonti di dati non ha risposto.

In questo momento lo sto facendo con un valore booleano all'interno della Classe A e della Classe B che indica se c'è un errore, e un altro oggetto per la memorizzazione del messaggio di errore effettivo. Il chiamante dovrà controllare questo valore booleano dopo aver effettuato una chiamata per vedere se si è verificato un errore.

Che cosa è un buon modello di progettazione per questo?

+1

Mi piace quando qualcuno fa la stessa identica domanda su cui sono sconcertato in questo momento. Grazie. – Martin

risposta

6

La risposta sarebbe molto ampio, quindi vorrei suggerire di utilizzare il:

Questo codice pseudo ha una sintassi simile a UML e 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() 

utilizzo Cliente:

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

Purtroppo, sembra un po 'complessa.

OOP si basa molto sul polimorfismo.

Quindi in Dao, si consente alla sottoclasse di recuperare i dati da qualsiasi luogo e lo si chiama dao.fetch().

Nel Strategy stesso, la sottoclasse esegue una procedura o l'altro (per evitare di avere un sacco di strane if 's, else' S, S switch', etc.).

Con State succede la stessa cosa. Invece di andare come:

if isBroken and itDoesntWork() and if ImAlive() 

ecc, ecc basta dire, "Hey, questo sarà il codice di uno Ci sono due connessioni e questo è quando v'è una sola."..

Infine, la facciata dice al cliente "Non preoccuparti, lo gestirò".

+0

Ottima risposta anche prima dello pseudo codice. – Martin

+0

+1 per il modello di stato. Sei curioso di sapere perché hai ricominciato tutto da capo la terza volta? –

+0

@Vinegar: Grazie. Circa il 3 °. Ho risposto in un'altra discussione – OscarRyz

0

vorrei suggerire una facciata che rappresentasse l'oggetto nel suo complesso (i dati del cliente) e una fabbrica che crea quell'oggetto recuperando da ciascuna fonte di dati e passando a quella sulla facciata (in il costruttore o come costruttore, a seconda di quanti ce ne sono). La singola classe con l'origine dati specifica avrebbe un metodo (su un'interfaccia comune o una classe base) per indicare se c'era un errore nel recupero dei dati. La facciata (o un delegato) sarebbe responsabile della combinazione dei dati.

Quindi la facciata avrebbe un metodo che restituirebbe una raccolta di un certo tipo che indica quali origini di dati l'oggetto rappresentato, o quali non hanno funzionato, a seconda di ciò che il cliente ha bisogno di sapere.

Problemi correlati