Domanda

Ho cercato un modo generico per gestire le associazioni bidirezionali e un modo per gestire gli aggiornamenti inversi nel codice Java scritto manualmente.

Per coloro che non sanno di cosa sto parlando, ecco un esempio. Di seguito sono riportati i miei attuali risultati di soluzioni (insoddisfacenti).

public class A {
    public B getB();
    public void setB(B b);
}

public class B {
    public List<A> getAs();
}

Ora, quando si aggiorna una delle estremità dell'associazione, al fine di mantenere la coerenza, anche l'altra estremità deve essere aggiornata. O manualmente ogni volta

a.setB(b);
b.getA().add(a);

o inserendo il codice corrispondente nel setter / getter e utilizzare un'implementazione Elenco personalizzata.

Ho trovato un progetto obsoleto, non mantenuto, le cui dipendenze non sono più disponibili ( https: //e-nspire-gemini.dev.java.net/ ). Risolve il problema utilizzando le annotazioni utilizzate per iniettare automaticamente il codice necessario.

Qualcuno conosce un altro framework che si occupa di questo in modo generico e discreto come ala gemini?

Ciao, Elmar

È stato utile?

Soluzione

collezioni google (dal codice interno di google) - http://code.google. com / p / google-collections / è compatibile con Java Generics (non solo compatibile, usa generics molto bene)

Class BiMap - http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?http://google -collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/package-summary.html consente le associazioni bidirezionali.

Alcune di queste classi dovrebbero entrare nel JDK 7.

Altri suggerimenti

A meno che non si estraggano i setter, sarà necessario fornire una sorta di meccanismo di notifica degli eventi. Se i tuoi oggetti sono JavaBeans, stai esaminando l'utilizzo di PropertyChangeSupport e l'attivazione di eventi di modifica delle proprietà.

Se lo fai (o hai qualche altro meccanismo per rilevare le modifiche), allora Glazed Lists fornisce un ObservableElementList che potrebbe essere facilmente utilizzato per gestire la sincronizzazione dell'associazione dalla fine dell'elenco (ovvero aggiungendo A all'elenco < A > automaticamente chiama a.setB (b)). L'altra direzione può essere gestita facilmente utilizzando il monitoraggio delle modifiche di proprietà (o equivalente).

Mi rendo conto che questa non è una soluzione generica, ma sembra che sarebbe una base facile per uno.

Nota che qualcosa del genere richiede un'implementazione dell'elenco speciale nella classe B - a dir poco soluzioni di tipo AOP che potresti gestirlo nel caso generale (cioè usando ArrayList o qualcosa del genere ).

Vorrei anche sottolineare che ciò che stai cercando di ottenere è qualcosa del santo graal dell'associazione dei dati. Ci sono alcune implementazioni decenti per il binding a livello di campo (cose come getter e setter) (vedi JGoodies binding e JSR 295 per esempi). Esiste anche un'implementazione davvero buona per l'associazione del tipo di elenco (Glazed Lists, di cui sopra). Usiamo entrambe le tecniche in concerto l'una con l'altra in quasi tutte le nostre applicazioni, ma non abbiamo mai provato ad andare in astratto quanto quello che stai chiedendo.

Se stavo progettando questo, guarderei qualcosa del genere:

AssociationBuilder.createAssociation(A a, Connector< A> ca, B b,  Connector< B> cb, Synchronizer< A,B> sync)

Il connettore è un'interfaccia che consente un'unica interfaccia per vari tipi di notifica di modifica. Synchronizer è un'interfaccia che viene chiamata per assicurarsi che entrambi gli oggetti siano sincronizzati ogni volta che uno di essi viene modificato.

sync(ChangeInfo info, A a, B b) // make sure that b reflects current state of a and vice-versa.  

ChangeInfo fornisce i dati su quale membro è stato modificato e quali sono state effettivamente le modifiche. Noi siamo. Se stai cercando di mantenere davvero questo generico, devi praticamente puntare l'implementazione di questo fino all'utente del framework.

Tenendo presente quanto sopra, sarebbe possibile disporre di una serie di connettori e sincronizzatori predefiniti che soddisfano criteri di associazione diversi.

È interessante notare che la firma del metodo sopra è abbastanza simile alla chiamata al metodo createSutoBinding () JSR 295. Gli oggetti proprietà sono l'equivalente di Connector. JSR 295 non ha il sincronizzatore (invece, hanno una strategia di associazione specificata come ENUM - inoltre JSR 295 funziona solo con la proprietà - & Gt; associazione di proprietà, cercando di associare un valore di campo di un oggetto all'elenco dell'oggetto) l'appartenenza a un altro oggetto non è nemmeno sul tavolo per loro).

Per avere un senso, questi vitelli saranno pari. Suggerisco un meccanismo pacchetto privato (in assenza di un amico) per mantenere la coerenza.

public final class A {
    private B b;
    public B getB() {
        return b;
    }
    public void setB(final B b) {
        if (b == this.b) {
            // Important!!
            return;
        }
        // Be a member of both Bs (hence check in getAs).
        if (b != null) {
            b.addA(this);
        }
        // Atomic commit to change.
        this.b = b;
        // Remove from old B.
        if (this.b != null) {
            this.b.removeA(this);
        }
    }
}

public final class B {
    private final List<A> as;
    /* pp */ void addA(A a) {
        if (a == null) {
            throw new NullPointerException();
        }
        // LinkedHashSet may be better under more demanding usage patterns.
        if (!as.contains(a)) {
            as.add(a);
        }
    }
    /* pp */ void removeA(A a) {
        if (a == null) {
            throw new NullPointerException();
        }
        as.removeA(a);
    }
    public List<A> getAs() {
        // Copy only those that really are associated with us.
        List<A> copy = new ArrayList<A>(as.size());
        for (A a : as) {
            if (a.getB() == this) {
                copy.add(a);
            }
        }
        return Collection.unmodifiableList(copy);
    }
}

(Disclaime: non testato o nemmeno compilato.)

Principalmente sicuro per le eccezioni (potrebbe verificarsi una perdita nel caso eccezionale). La sicurezza dei thread, molte, prestazioni, librerie, ecc., Viene lasciata come esercizio al lettore interessato.

Grazie per tutti i suggerimenti. Ma nessuno si avvicinava a quello che cercavo, probabilmente ho formulato la domanda in modo sbagliato.

Stavo cercando un sostituto dei gemelli, quindi un modo per gestirlo in modo discreto, senza inquinare il codice con controlli infiniti e implementazioni speciali della Lista. Ciò richiede ovviamente un approccio basato su AOP, come suggerito da Kevin.

Quando mi sono guardato un po 'di più ho trovato un pacchetto di gemini su cnet che contiene tutte le fonti e le dipendenze con le fonti. Le fonti mancanti per le dipendenze erano l'unica preoccupazione che mi impediva di usarlo. Da ora tutti i sorgenti sono disponibili, i bug possono essere corretti. Nel caso qualcuno lo cerchi: http://www.download.com/Gemini /3000-2413_4-10440077.html

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