2011-12-04 10 views
5

Ho tre classi, un utente astratto e due specifici: NormalUser che contiene un ArrayList di uno o più oggetti Address che possono essere diversi (domestico, internazionale, personalizzato ecc.) E quindi il Classe di amministrazione che ha un metodo che restituisce true. Entrambi contengono più metodi che non sono correlati tra loro.Ereditarietà Java ed evitando l'uso costante di instanceof

abstract class User{ 
    public User(String username, String pw){ 
... 

} 

public class NormalUser extends User{ 
... 
    private ArrayList<Address> addresses; 

... 

    public void addAdress(ArrayList<Address> address){ 
     addresses.addAll(address); 
} 

public class Admin extends User{ 

... 
    public boolean getIsAdmin(){ 
     return true; 
    } 
} 

Ora, in un'altra classe se faccio 4 oggetti utente in questo modo, per esempio:

ArrayList<User> users; 

    users.add(new NormalUser("1", "pw"); 
    users.add(new NormalUser("2", "pw"); 
    users.add(new NormalUser("3", "pw"); 
    users.add(new NormalUser("4", "pw"); 
    users.add(new Admin("5", "pw")); 
    users.add(new NormalUser("6", "pw"); 

e dire che voglio utilizzare il metodo addAddress in NormalUser, allora devo downcast l'utente specfic in agli utenti di NormalUser, prima di poter utilizzare il metodo addAddress in NormalUser come questo:

 if (user instanceof NormalUser){ 
     NormalUser normal = (NormalUser) user; 
     normal.addAddress(...) 
     } 

il motivo per cui mi piacerebbe sia NormalUser e Admin essere un utente è così che io possa elaborare insieme al momento del login.

Ho pensato di aggiungere l'addEmail alla classe User e quindi sovrascriverlo nella classe NormalUser, ma dovrei farlo per ogni metodo nella classe NormalUser, più Admin lo erediterebbe dal Anche l'utente, quando non ha bisogno di quella funzionalità.

Domanda 1: C'è un modo migliore per farlo perché ho sentito che usare instanceof è una cosa negativa? e dovrei usare instanceof ogni volta che utilizzo un metodo specifico per la classe NormalUser.

Quesiton 2: È un elenco array di indirizzi indirizzi il modo migliore per collegare il RegularUser a specifici indirizzi/(oggetti)?

Al momento non sono presenti database.

Così, per esempio all'utente una ha 2 indirizzi uno nazionale e uno internazionale, e l'utente B ha solo un indirizzo interno, l'utente c ha una domestica e un indirizzo personalizzato, ecc

Grazie.

PS. Ho cercato estensivamente i post precedenti ma non ho trovato una soluzione. In entrambi i miei libri Java entrambi mostrano esempi di utilizzo di instanceof ma nessuna menzione del fatto che sia una cattiva pratica.

+0

In questo caso specifico, temo di non poter dire veramente quale sia il migliore, ma no, 'instanceof' non è per definizione una cosa negativa. Non dovresti esagerare quando il polimorfismo è più appropriato. –

+0

In relazione a 'instanceof': dovresti riconsiderare il tuo progetto in modo tale da non chiamare mai' addAddress' su un utente di base'. Dovresti chiamare questo metodo solo quando ti trovi in ​​un blocco di codice progettato specificamente per 'NormalUser'. – toto2

+0

c'è qualche buona ragione per gli amministratori di non avere indirizzi? – soulcheck

risposta

3

È possibile utilizzare Visitor pattern - un po 'goffo e leggermente illeggibile, ma probabilmente la soluzione migliore per il tuo problema.

In realtà la tua soluzione con la spinta della classe addEmail alla base non è poi così male. È sufficiente fornire un'implementazione vuota nella base User e eseguire l'override in RegularUser. Se si desidera verificare se l'istanza User supporta l'aggiunta di e-mail, fornire un altro metodo come supportsAddEmail restituendo false per impostazione predefinita e true quando si sostituisce addEmail.

+0

Ma la Admin non erediterà l'addAddress (anche se è vuoto)? – Brah

+0

Sì, questo significa che puoi chiamare 'Admin.addEmail()' che non fa nulla (no-op). Questo è il motivo per cui suggerisco 'supportsAddEmail', ma non sembra davvero una buona idea. Bit non è esattamente quello che vuoi? Aggiungi e-mail se l'utente è 'NormalUser', non fare altrimenti. –

+0

Penso che aggiungere "addEmail" alla classe base sia una buona idea e innocuo. Per quanto riguarda la sua natura no-op, puoi pensare che "qualcuno ha detto all'oggetto Admin di un indirizzo email, e se l'amministratore non si preoccupa, così sia". Dove diventa più brutto è se devi mettere 'getEmail()' nella classe base; in questo caso, alcune implementazioni dovrebbero generare un'eccezione, che trovo brutta. Se lo fai, almeno un metodo come 'supportsGetEmail()'. La cosa migliore sarebbe se i siti di chiamata sapessero quale sottoclasse Utente hanno, quindi puoi aggiungere 'getEmail()' solo a NormalUser. – yshavit

0

Penso che la soluzione più semplice sia creare una UserList di classe che contenga un elenco di NormalUser e un elenco di Admin. Un'istanza della classe UserList sostituirà l'elenco originale.L'UserList classe potrebbe fornire alcuni metodi come ad esempio:

  • utente getUser (indice i) // implementato con le due liste

  • removeuser utente (indice i) // implementato con le due liste

  • NormalUser getNormalUser (indice i) // implementato con l'elenco utente normale
  • NormalUser removeNormalUser (indice i) // implementato con l'elenco utente normale
  • Admin GetAdmin (indice i) // implementato con l'elenco utente admin
  • Admin removeAdmin (indice i) // implementato con l'elenco utente admin
  • ....

Tutto il codice per la gestione delle liste appropriato sarebbe incapsulato nella classe UserList . Potresti avere metodi che usano entrambi gli elenchi o solo un elenco, a seconda di cosa devi fare con gli utenti. Le classi che interagiscono con UserList non saprebbero se ci sono solo uno o due elenchi in UserList.

+0

Grazie per la risposta Phil, mi sembra una buona idea, anche se mi sarebbe piaciuto non dover creare una nuova classe solo per tenere le liste. Sono nuovo a Java, ma se per esempio avevo una superclasse di animali, poi una sottoclasse di cani e gatti. Se avessi una lista di animali con cani e gatti e volessi chiamare la corteccia() sui cani, allora dovrei creare una lista di cani per farlo correttamente? - Mi sembra solo controintuitivo:/ – Brah

+0

Ciao. Se io dove tu, creerei (1) un elenco per i gatti e (2) un elenco per i cani. Considera che hai 10000 cani e 10000 gatti. Se separi gli elenchi, sarà molto più veloce trovare tutti i cani, quindi se avessi una sola lista con 20000 animali mescolati insieme. Quando hai bisogno di chiamare un metodo come la corteccia() devi solo elaborare l'elenco dei cani invece di elaborare 20.000 animali e dover controllare se sono cani o gatti prima di chiamare la corteccia(). Le prestazioni dovrebbero essere molto migliori con due elenchi se si hanno molti elementi. – Phil