2011-09-20 9 views
10

Sto progettando un motore di gioco in Java.Java: Applicazione di oggetti doppiamente collegati

Al centro di questo motore esistono le due classi Asset e Attribute, in cui un asset ha un elenco di attributi. La maggior parte degli Attributi non ha bisogno di link per tornare al loro Attributo, il che significa che gli Attributi possono e spesso appaiono negli elenchi di più di un Bene. Tuttavia, esiste un'estensione dell'Attributo chiamata UniqueAttribute, che è un'implementazione per quelli che sono specifici del loro Asset e utilizza un link back.

  1. Idealmente, il metodo AddAttribute di mio Asset sarebbe simile a questo se ho tagliato fuori l'altro codice:

    public void addAttribute(Attribute attribute){ 
        if(attribute instanceof UniqueAttribute) 
        ((UniqueAttribute)attribute).setAsset(this); 
        attributeList.add(attribute); 
    } 
    

    Purtroppo, poiché vivono in diversi pacchetti, UniqueAttribute.setAsset() deve essere pubblico . Questo lascia il metodo aperto agli utenti esterni del motore con cui pasticciare, e anche se potrei semplicemente farlo a mano dicendo che usare direttamente questo metodo è un bug - sembra piuttosto sciatto.

  2. La seconda opzione è quella di fornire al UniqueAttribute con l'attività per la costruzione, il che significa che il codice al momento della creazione sarebbe simile a questa:

    asset.addAttribute(new UniqueAttribute(asset)); 
    

    Anche se posso aggiungere un check-e- gettabile o asserito per confermare che la risorsa corretta è passata, fondamentalmente sto facendo affidamento sull'utente per connettere i due, che anch'io preferirei non fare.

  3. La terza opzione consiste nel mordere il proiettile e inserire tutti e 50 i file java nello stesso pacchetto in modo da poter utilizzare solo la visiblity standard.

C'è una sorta di modello o qualcosa che vi aiuterà collegare questi due insieme senza esporre i fili, o costringendomi a mettere tutto in un unico pacchetto di massa?

Rant irrilevante: non mi è mai piaciuto che il concetto di sottofacili in java non sia stato realmente ampliato in alcun modo significativo. Un sotto pacchetto, per quanto riguarda java, è semplicemente un pacchetto diverso, e ci sono state molte occasioni in cui ho potuto fare con più modificatori di visibilità direttamente correlati a questo.

+0

forse l'opzione 2 con una sorta di factory che conosce la relazione tra attributi e risorse univoci? –

+0

Mentre suppongo che avere regole speciali per i pacchetti secondari possa aver funzionato, non è quasi mai necessario (dato che puoi usare sistemi come Spring o OSGi per forzare la separazione tra interfaccia e implementazione) e renderebbe le cose molto più complesse per molto piccolo guadagno. Un'implementazione semplice e affidabile è più importante di una funzionalità "carina" ma complessa. –

risposta

2

Il mio suggerimento sarebbe che Asset, Attribute e UniqueAttribute dovrebbero essere tutti nello stesso pacchetto (possibilmente insieme ad alcune altre classi "motore" di base). Quindi puoi utilizzare la visibilità del pacchetto standard per UniqueAttribute.setAsset.

Non è necessario inserire tutte le altre classi nello stesso pacchetto: il metodo Asset.addAttribute deve essere pubblico e accessibile da altri pacchetti, in modo che il resto dell'applicazione possa utilizzarlo direttamente.

Quindi la soluzione potrebbe essere denominata "3-" nella categorizzazione.

Come alcuni punti più generali, in considerazione anche:

  • Sia che si ha realmente bisogno la complessità di entrambi gli attributi e UniqueAttributes - non sono sicuro che davvero, dopo aver implementato un modello di oggetti di gioco abbastanza complesso senza bisogno di qualcosa che assomiglia a un UniqueAttribute. Se UniqueAttribute "ha bisogno di un link" allora forse sta cercando di essere troppo intelligente/fare troppo?
  • Anche se ne hai bisogno entrambi, vuoi davvero scrivere codice che li tratti allo stesso modo/come parte della stessa gerarchia di oggetti? sembrano abbastanza concettualmente diversi e finirai per scrivere un sacco di codice condizionale se confilerai i due .....
  • Ci sono vari altri vantaggi degli attributi che sono costantemente condivisi e immutabili - è meglio per l'utilizzo della memoria, la concorrenza e testabilità tra le altre cose. E poiché sono presumibilmente piuttosto piccoli, il costo della semantica copy-on-write è banale nei casi in cui ne hai bisogno.
+0

Precedentemente stavo usando il metodo uno sopra, quindi UniqueAttribute non è nuovo - sto solo guardando alcuni miglioramenti fondamentali. Il tuo punto due: mi sento di avere troppo codice condizionale se separo i due, in quanto vi sono molti punti in cui l'elenco degli attributi è iterato per uno specifico o tipo. Tuttavia, è perspicace - ci penserò di più. – Numeron

+0

Ah capisco perché vuoi i collegamenti posteriori ora! Se l'iterazione su tutti gli oggetti con un attributo specifico è il problema, allora potresti prendere in considerazione la possibilità di tenere un indice separato (HashSet forse?) Di tutti gli oggetti che hanno l'attributo importante. È possibile aggiornare questo set quando gli oggetti vengono aggiunti/rimossi o quando gli attributi vengono modificati. Sebbene sia necessario mantenere questo indice sincronizzato, questo è efficiente, abbastanza facile da testare ed evita la necessità di inserire la logica complessa negli Attributi stessi. – mikera

0

Beh, in fondo si vuole fare 3 cose: metodo setAsset

  1. rendere visibile all'interno della confezione contenente classe Asset
  2. metodo nascondere setAsset da tutti gli altri pacchetti
  3. non utilizzano sottopacchetti per raggiungere quello

Questo è un po 'problematico: se si dichiara pubblico quel metodo nella classe Attributo tutte le altre classi compreso th al pacchetto (chiamiamolo AttributePackage), non è possibile impedire a l'utente di includere da qualche parte quel pacchetto.

D'altra parte si potrebbe effettuare le seguenti operazioni:

  1. creare un'interfaccia che contiene solo il metodo attributo che l'utente deve utilizzare, chiamiamolo AttributeInterface
  2. make Attributo implementare tale interfaccia
  3. aggiungere AttributeInterface a un nuovo pacchetto

Un utente che desidera utilizzare la classe di attributi deve utilizzarlo tramite AttributeInterface nel frattempo Asset utilizzerà direttamente la classe Attribute per accedere a tutti i metodi.

Farò un esempio:

//attribute interface package 
public interface AttributeInterface{ 
    public void publicAttributeMethodClientShouldUse(); 
} 

//attribute package 
public class Attribute{ 
    public void setAsset(Asset a); 
    public void publicAttributeMethodClientShouldUse(); 
} 

Asset farà riferimento direttamente Attributo intanto utente deve fare riferimento AttributeInterface. Spero di essere chiaro.

+0

Non sono sicuro di come l'utente sarà in grado di creare un attributo con un collegamento al suo asset in questa istanza? Implementare l'interfaccia significherà che è solo un Attributo standard senza accesso a getAsset(), e l'estensione della classe ha lo stesso problema che ho presentato nella domanda. – Numeron

2

vorrei aggiungere un metodo di callback in attributo che viene chiamato quando viene aggiunto a un bene un'istanza di attributo:

class Attribute { 
    protected void addedToAsset(Asset asset) { 
     // do nothing 
    } 
} 

Questo metodo sarebbe chiamato nel metodo AddAttribute

class Asset { 
    public void addAttribute(Attribute attribute) { 
     attributeList.add(attribute); 
     attribute.addedToAsset(this); 
    } 

} 

E il metodo sarebbe sovrascritto in UniqueAttribute per controllare il collegamento con Asset:

class UniqueAttribute extends Attribute { 
    Asset asset; 
    protected void addedToAsset(Asset asset) { 
     // manage the previous link if needed 
     if (this.asset != null) { ... } 
     this.asset = asset; 
    } 
} 

Con questa soluzione, Asset e Attributo dovrebbero essere messi nello stesso pacchetto. Ma UniqueAttribute potrebbe essere in qualsiasi pacchetto tu voglia.

1

Modificare la vostra opzione scond

asset.addAttribute(new UniqueAttribute(asset)); 

come questo:

class UniqueAttribute { 
Asset asset; 
    public UniqueAttribute(Asset asset) { this.asset = asset; asset.addAttribute(this); } 
} 

fare un approccio simile per l'attributo non univoco. Ciò significa che invece di usare addAttribute() dall'esterno, usarlo solo all'interno dei costruttori.

Un'altra opzione consiste nell'aggiungere due metodi di fabbrica a Asset: createAttribute() e createUniqueAttribute();

+0

In questo modo anche l'asset di UniqueAttribute può essere finalizzato a ridurre la mutabilità UniqueAttributes. – OliverS

+0

Anche se questo significa che ho lo stesso problema sopra, tranne che sarò in conflitto con la visibilità di addAttribute invece di setAsset. – Numeron

0

In primo luogo, queste entità do sembrano così strettamente correlate da essere inserite nello stesso pacchetto. Li metterei nello stesso pacchetto e rendere privato il pacchetto metodo addAttribute.

Tenete a mente che, dall'introduzione di AccessibleObject in Java, la visibilità e il controllo degli accessi nella lingua sono diventati solo cosmetici ... Chiunque usi la vostra libreria può prendere lezioni e rendere i metodi e i campi privati ​​accessibili e modificabili! Diavolo, possono anche modificare i membri di final! Quindi, non mettere molta enfasi sull'aspetto di visibilità e solo assicurarsi che il flusso del modello e del metodo abbia senso per gli utenti e funzioni correttamente.

+0

Spiacente, intendevo il metodo 'UniqueAttribute.setAsset()' da rendere pacchetto-privato. – vagelis

Problemi correlati