Domanda

Supponiamo che io sono i seguenti tipi di dati:

class Customer {
  String id; // unique
  OtherCustData someOtherData;
}

class Service {
  String url; // unique
  OtherServiceData someOtherData;
}

class LastConnection {
  Date date;
  OtherConnData someOtherData; // like request or response
}

Ora ho bisogno di ricordare quando ciascuno dei clienti connessi a ciascuno dei servizi.
Vorrei rendere la struttura:

Map<Customer, Map<Service, LastConnection>> lastConnections;

O, per essere in grado di cercare da IDS e non dover scrivere tutto il uguale () e hashCode ():

Map<String, Map<String, LastConnection>> lastConnections;

Ora ho potuto accedere ai dati LastConnection da

LastConnection connection = lastConnections.get(custId).get(srvUrl);

Tutto questo sembra brutto, soprattutto che devo passare come parametri a decine di metodi che prevedono mappa di mappe di LastConnections, così sto pensando di creare le mie classi che sarebbe simile a quanto segue:

class CustomerConnections extends HashMap<String, LastConnection> {
}

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

Ok, ho imparato già che l'ereditarietà è 3v1l, quindi proviamo composizione:

class CustomerConnections {
    Map<String, LastConnection> customerConnections;
    LastConnection get(String srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    ... // all other needed operations;
}

class AllConnections {
    Map<String, CustomerConnections> allConnections;
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
    public CustomerConnection get(String custId) {
        return allConnections.get(custId);
    }
    ... // all other needed operations;
}

Il problema è che io non sono sicuro di quale sarebbe l'approccio migliore rispetto di principi solidi e tutte le migliori pratiche. La creazione di classi che non fanno nulla se non si estende collezioni già esistenti sembra moltiplicare le entità oltre il necessario, ma renderebbe il mio codice più chiaro (soprattutto quando ci sono livelli successivi - come Mappa di AllConnections per mese e così via). Eventuali indicazioni?

È stato utile?

Soluzione

  

La creazione di classi che non fanno altro   tranne estendentesi già esistente   collezioni sembra come moltiplicando   entità al di là necessità

vorrei cambiare estendono per incapsulare. Si nasconde i dettagli di come queste informazioni vengono memorizzate. I clienti della vostra classe non hanno bisogno di sapere come si sta fornendo loro con la storia di connessione del cliente. Penso che questa sia una buona idea, dato che è possibile cambiare il modello di fondo senza avere clienti del api cambiano il loro codice.

  

, ma renderebbe il mio codice più chiaro

Questo è grande ed è un buon motivo per farlo. YourClass.getCustomerConnection (CID) è molto più chiara di yourCollection.get (id) .get (id) .getConnection (). Hai bisogno di fare la vita delle persone che utilizzano questo codice più facile, anche se si è quella persona.

  

(soprattutto quando ci sono livelli successivi - come Mappa di AllConnections per mese e così via)

Bene, allora si sta progettando avanti e rendere il vostro codice estensibile. Che è buona pratica OO. A mio parere il conculsion avete raggiunto sul proprio è quello che vorrei fare.

Altri suggerimenti

Vorrei creare un oggetto dedicato per la memorizzazione di queste informazioni. Quello che si sta creando è un Gestione oggetto, piuttosto che una collezione semplice.

I potrebbe non renderlo deriva da una mappa o di altra classe di raccolta ben noto, dal momento che la semantica di come si memorizza queste informazioni possono cambiare in futuro.

Invece implementare una classe che lega insieme un cliente e la sua connessione, e dentro quella classe utilizzare la classe di raccolta appropriato (che sei libero di cambiare in seguito senza influenzare l'interfaccia e il resto del codice)

Il tuo cliente / Connection Manager di classe è più di un semplice contenitore. E 'possibile memorizzare i meta-dati (ad esempio, quando è stato stabilito questo rapporto). E 'possibile effettuare ricerche sulle connessioni dato informazioni sui clienti (se si richiede). E 'in grado di gestire i duplicati come si richiede, piuttosto che come la classe insieme sottostante li ecc ecc Si può facilmente introdurre in debug / monitoraggio dello sfruttamento forestale / prestazioni per capire facilmente cosa sta succedendo gestisce.

Credo che si dovrebbe anche considerare come le collezioni stanno per essere utilizzato e in che modo si ottiene i dati:

  • Se sono semplici set di risultati da visualizzare in una pagina (per esempio), quindi utilizzando le collezioni standard, sembra ragionevole - e quindi è possibile utilizzare un sacco di librerie standard di manipolarli
  • .
  • D'altra parte, se sono mutevoli e le eventuali modifiche devono essere persistenti (ad esempio), quindi incapsulare all'interno delle proprie classi potrebbe essere preferibile (che può quindi scrivere le modifiche ai database, ecc).

Come si ottiene e persistono i tuoi dati? Se è memorizzato in un database, allora forse è possibile utilizzare SQL per selezionare LastConnections da parte del cliente e / o servizio e / o del mese, invece di dover mantenere le strutture di dati da soli (e solo tornare elenchi semplici o mappe di connessioni o conteggi di connessioni ). O forse non si vuole eseguire una query per ogni richiesta, quindi c'è bisogno di mantenere l'intero datastructure in memoria.

L'incapsulamento è generalmente una buona cosa, però, soprattutto in quanto può aiutare a effettuata secondo le Legge di Demetra - forse si può spingere alcune delle operazioni che si eseguono sulle collezioni di nuovo nella classe AllConnections (che è effettivamente un DAO). Questo spesso può aiutare a test di unità.

Inoltre, il motivo per cui si sta estendendo HashMap considerato il male qui, considerando che solo si desidera aggiungere un metodo di supporto banale? Nel codice per AllConnections, AllConnections sarà sempre si comportano nello stesso modo come un HashMap - è polimorfico sostituibili. Naturalmente, si sta potenzialmente te stesso blocco nello usando HashMap (piuttosto che TreeMap, ecc), ma che probabilmente non importa dal momento che ha gli stessi metodi pubblici come mappa. Tuttavia, se si desidera realmente vuole fare davvero questo non dipenderà da come si intende utilizzare le collezioni - io non credo che si dovrebbe sconto automaticamente l'ereditarietà dell'implementazione come sempre male (solo di solito è !)

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

Why not use custId+"#"+srvurl as a key in a simple Map<String, LastConnection>?

Or use a Tuple or Pair class as key that contains the two IDs and implements hashCode() and equals() - the "cleanest" OO solution.

Why are you maintaining the relationships between objects outside of those objects.

I'd suggest something like the following:

public class Customer 
{
  public List<LastConnection> getConnectionHistory() 
  {
    ... 
  }

  public List<LastConnection> getConnectionHistory(Service service) 
  {
    ...
  }

  public List<LastConnection> getConnectionHistory(Date since) 
  {
    ...
  }
}

public class LastConnection
{
  public Date getConnectionTime() 
  {
    ...
  }

  public Service getService()
  {
    ...
  }
}

You then pass List<Customer> to the methods that use this information.

You could create a class that implements Map<K,V>, and internally delegate to a container map:

class CustomerConnections implements Map<String,LastConnection> {
    private Map<String, LastConnection> customerConnections;

    @Override
    public LastConnection get(Object srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    // all other needed operations;
}

The nice thing with this approach is that you can pass around a Map which has a standard, well-defined contract, but you avoid extending library classes, which is often frowned upon.

EDIT : As pointed out below, this does have the downside of requiring you to implement a lot of methods that do nothing short of delegate to the underlying collection

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top