2011-11-01 13 views
8

Ho due classi Studente e Tutor. Il tutor è fondamentalmente uno studente (il tutor estende lo studente) che ha facoltà. Una volta che il suo contratto è completo, torna ad essere solo uno studente. Quindi posso in qualche modo convertirlo al suo "precedente" rotolo di studenti?Java, è possibile 'convertire' oggetto da sottoclasse in oggetto dalla superclasse

+0

È possibile che non si debba utilizzare l'ereditarietà per modellare questa relazione. In base alla tua breve descrizione potresti prendere in considerazione la creazione di un wrapper Tutor che prende uno Studente in fase di costruzione. Quindi, una volta completato il contratto, è sufficiente lasciare che il riferimento al wrapper non rientri nell'ambito e continuare a lavorare direttamente con l'istanza di Student. –

+2

puoi fornire un po 'più di contesto alla tua domanda? imho dipende davvero da cosa stai cercando di ottenere. magari aggiungendo un membro 'boolean isTutor;' o semplicemente mantenendo un elenco di studenti che sono anche tutor è sufficiente. non c'è bisogno di modellare tutto con schemi OO solo perché è possibile. – kritzikratzi

+0

@kritzikratzi Amo il tuo commento "Non c'è bisogno di modellare tutto con OO ... solo perché puoi". Non potrei essere più d'accordo! – corsiKa

risposta

5

Quello che vuoi veramente fare qui è usare composition and not inheritance. Conservare tutti gli oggetti come tipo Student e quindi assegnare temporaneamente il comportamento di TutorRole come richiesto a ciascuna istanza di Student.

Con questo modello la classe Student conterrà una proprietà (variabile membro) di tipo TutorRole che è possibile aggiungere o rimuovere in fase di runtime. L'aggiunta di un metodo isTutor() ti consentirà di scoprire se uno studente è un tutor al runtime in modo chiaro e conciso.

La classe TutorRole incapsulerà il comportamento (cioè i metodi) di essere un Tutor.

/* 
* The TutorRole can be set at runtime 
*/ 
public class Student { 

    private String facultyId; 

    private TutorRole tutorRole = null; 

    public boolean isTutor() { 
     return !(tutorRole == null); 
    } 

    public void doTutorStuff() { 
     if(isTutor()) { 
      tutorRole.doTutorStuff(); 
     } 
     else { 
      throw new NotTutorException(); 
     } 
    } 

    public void setTutorRole(TutorRole tutorRole) { 
     this.tutorRole = tutorRole; 
    } 
} 

/* 
* Ideally this class should implement a generic interface, but I'll keep this simple 
*/ 
public class TutorRole { 

    public void doTutorStuff() { 
     // implementation here 
    } 
} 

/* 
* Now let's use our classes... 
*/ 
Student st = new Student(); // not a tutor 
st.setTutorRole(new TutorRole()); // now a tutor 
if(st.isTutor()) { 
    st.doTutorStuff(); 
} 
st.setTutorRole(null); // not a tutor anymore 

Un approccio alternativo è quello di avere una classe Tutor contiene un riferimento a un oggetto Student, ma dipende da come si sta andando ad essere l'interazione con lo studente e gli oggetti Tutor del modo in cui intorno si vuole codificare questo .

2

Puoi lanciare il Tutor come uno studente in modo che il codice lo tratta come tale al momento della compilazione, ma l'oggetto rimarrà un Tutor, in modo da chiamare qualsiasi metodi sostituiti farà sì che la versione della classe Tutor per essere chiamato.

L'unico modo per eseguire il tipo di "conversione" che stai cercando è creare un nuovo oggetto Studente e assegnargli tutte le proprietà del Tutor.

Poiché stai riscontrando che è necessario eseguire questa conversione, potresti voler ripensare alla struttura della classe. Ad esempio, forse sia gli studenti che i tutor dovrebbero essere solo persone e ogni persona può avere il ruolo di studente o insegnante.

+0

Potresti per favore elaborare questo? Non sono sicuro di come farlo? – vedran

+0

@vedran: se desideri modificare la tua risposta per fornire parte del tuo codice corrente e una spiegazione più completa di ciò che stai cercando di realizzare convertendo una persona da un tipo all'altro, posso darti un feedback migliore. – StriplingWarrior

3

Dopo aver creato un'istanza di un tipo (ad esempio, Tutor), questo è il tipo di esecuzione che avrà l'istanza. Questo non può più essere cambiato.

Alcune alternative:

  • Give Student qualche costruttore che accetta un altro Student istanza e copie sui campi pertinenti. Un cosiddetto costruttore di copie. In questo modo, potresti facilmente creare una nuova istanza Student basata sul tuo Tutor e utilizzarla.
  • Se è importante conservare l'istanza effettiva piuttosto che crearne una copia (forse hai mantenuto i riferimenti dappertutto), sarebbe meglio separare il ruolo dalla classe. Crea una classe FacultyMember o qualcosa di simile e attiva i ruoli Student e Tutor. Quindi puoi modificare il ruolo di FacultyMember in seguito.
1

Non è possibile modificare il tipo di oggetto in Java. Probabilmente il modo più semplice per ottenere il tuo modo è quello di clonare tutti i parametri da Tutor in un nuovo oggetto Studente.

1

Si potrebbe semplicemente scrivere un metodo come TutorToStudent() su Tutor e creare un nuovo Studente dal proprio Tutor. Se lanci, finirai con l'oggetto che è ancora un Tutor.

Si potrebbe anche considerare di rinunciare all'ereditarietà in questo caso e basta avere una bandiera che indica se questo studente è o meno un Tutor.

+0

Ma se avessi una collezione di Studenti, manterrebbe comunque il vecchio Tutor, non il nuovo Studente normale. – corsiKa

+0

@glowcoder: vero ma questo vale per la maggior parte delle soluzioni che mantengono ancora la gerarchia dell'ereditarietà e tentano in qualche modo di trasformare il Tutor in uno Studente. Come ogni soluzione, non risolve tutti i casi e ovviamente occorrerà un codice aggiuntivo per giustificare casi come quelli che hai menzionato. –

+0

sì, vale per le soluzioni che mantengono la gerarchia dell'ereditarietà. Ma è una buona pratica "Favorire la composizione sull'eredità". È molto meglio avere un ruolo 'Studente' e un ruolo' Tutor' e avere semplicemente un'istanza (o lista) di un ruolo (o ruoli, se si usa una lista). – corsiKa

1
  1. È possibile creare un nuovo Studente con le stesse informazioni del Tutor e scartare l'oggetto originale. O con un costruttore di copie Student(Student original) o un metodo Student toStudent() Questo è il modo rapido e sporco.

  2. Invece di fare Tutor si estendono direttamente uno studente, rendendo i Tutor dati e comportamenti specifici in un Decorator. O, meglio ancora, rendere entrambi i decoratori Tutor e Student di un oggetto People che include tutti. Questo è uno dei modi migliori per farlo.

  3. Fai il Tutor e Student in un enum Type e tenere premuto questo campo in People, questo è più facile ma meno estensibili quanto sopra, in realtà dipende dalla natura delle differenze tra Tutor e Student.

1

Non esiste una cosa come "conversione" riportarlo a uno studente, è un tutore, e un tutor è già uno studente.

Tuttavia, potrebbe esserci qualche valore nel rendere generico l'accesso di questo oggetto, in modo da utilizzare solo il metodo studente. Ci sono diversi idiomi in Java per questo.

1) È possibile utilizzare l'API studente esclusivamente nel codice, ad eccezione della porzione Tutor.

2) È possibile avere un metodo "toStudent/toTutor" per gli oggetti, che consente loro di restituire oggetti specifici del ruolo.

// La mia preferenza 3) È possibile utilizzare le interfacce. Chiedi a Tutor e Student di essere interfacce e crea i tuoi oggetti utilizzando l'implementazione dell'interfaccia. Se fai riferimento a oggetti che usano interfacce minime, piuttosto che modelli di ereditarietà pesanti, il tuo codice probabilmente migliorerà in futuro.

4

Penso, questo grido di contenimento e programmazione dell'interfaccia.

ne dite di questo:

interface IStudent 
{ 
    String getName(); 
    int getStudentId(); 
} 

interface IFacultyMember 
{ 
    int getFacultyId(); 
} 

class Student 
    implements IStudent 
{ 
    String name; 
    int id; 

    public String getName() { return name; } 
    public int getStudentId() { return id; } 
} 

class Tutor 
    implements IStudent, IFacultyMember 
{ 
    Student student; 
    int facultyId; 

    public Tutor (Student student, int facultyId) 
    { 
    this.student = student; 
    this.facultyId = facultyId; 
    } 

    public String getName() { return student.getName(); } 
    public int getStudentId() { return student.getStudentId(); } 
    public int getFacultyId() { return facultyId; }; 
} 

In questo modo, il vostro studente rimane uno studente, anche se si muove nella posizione di Tutor. Quando scade il termine del tutor, solo GC il record del tutor.

La documentazione dello studente, al contrario, sarà ancora disponibile nei Servizi centrali.

Problemi correlati