2011-11-01 97 views
8

我有兩個類Student和Tutor。導師基本上是一名學生(導師延伸學生)誰擁有facultyID。一旦他的合同完成,他就回到只是一名學生。那麼我能否以某種方式將他轉回他以前的學生卷?Java,是否有可能將對象從子類轉換爲超類對象

+0

可能你不應該使用繼承來模擬這種關係。根據您的簡短描述,您可能需要考慮創建一個Tutor包裝器,它在施工時需要一名學生。然後,當合同完成時,您可以簡單地讓對包裝的引用超出範圍,並繼續直接與Student實例一起工作。 –

+2

你能否提供更多的背景給你的問題? imho它真的取決於你想要達到的目標。 也許增加一個'布爾isTutor;'成員或者乾脆保留一個也是導師的學生列表就足夠了。不需要僅僅因爲可以用OO模式對所有東西進行建模。 – kritzikratzi

+0

@kritzikratzi我喜歡你的評論「沒有必要用OO建模所有東西......只是因爲你可以」。不能同意更多! – corsiKa

回答

5

你真正想要做的是使用composition and not inheritance。將所有對象保留爲類型Student,然後按需要臨時將TutorRole的行爲分配給每個實例Student

使用此設計,您的Student類將包含類型爲TutorRole的屬性(成員變量),您可以在運行時添加或刪除該屬性。添加一個isTutor()方法將允許您以清晰簡潔的方式確定學生是否在運行時是導師。

TutorRole類將封裝作爲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 

的另一種方法是有一個Tutor類包含對Student對象的引用,但是這取決於你將如何與學生進行互動,各地要編碼這個導師在哪條路對象。

2

你可以轉換作爲學生的導師,所以你的代碼在編譯時對待他,但對象將保持一個導師,所以調用任何重寫的方法將導致調用Tutor類的版本。

要做的那種「轉換」,你正在尋找的唯一方法是創建一個新的學生對象,並給它所有的導師的屬性。

由於您發現需要進行此轉換,因此您可能需要重新考慮類結構。例如,也許學生和導師都應該只是人,而每個人都可以有學生或教師的角色。

+0

請您詳細說明一下嗎?我不知道該怎麼做? – vedran

+0

@vedran:如果你想編輯你的答案來提供你當前的一些代碼,並且更全面地解釋你將一個人從一種類型轉換爲另一種類型所要達到的目標,我可以給你一些更好的反饋。 – StriplingWarrior

3

一旦你創建了某種類型的實例(例如,Tutor),那就是實例會有的運行時類型。這不能再改變了。

一些替代方案:

  • Student一些構造函數接受另一個Student實例,並拷貝了相關的字段。一個所謂的拷貝構造函數。這樣,您可以根據您的Tutor輕鬆創建一個新的Student實例,然後使用它。
  • 如果保留實際實例而不是創建一些副本很重要(也許您已經在整個地方保留引用),那麼最好將角色與類分開。製作一些FacultyMember課程或將StudentTutor轉爲角色。然後,您可以稍後更改FacultyMember的角色。
1

您不能在Java中更改對象類型。可能最簡單的方法是將Tutor的所有參數克隆到新的Student對象中。

1

您可以在Tutor上寫一個像TutorToStudent()這樣的方法,並從您的導師中創建一個新學生。如果你演員,你會最終與對象仍然是一個導師。

你也可以考慮在這種情況下放棄繼承,只是有一個標誌表明這個學生是否是導師。

+0

但是,如果你有一個學生集合,它仍然會保持老導師,而不是新的正規學生。 – corsiKa

+0

@ glowcoder:沒錯,但對於大多數仍然保持繼承層次並試圖以某種方式將Tutor轉換爲Student的解決方案。就像任何解決方案一樣,它不能解決所有情況,顯然需要額外的編碼來解決像您提到的情況。 –

+0

是的,它適用於維護繼承層次的解決方案。但是,「贊成組合繼承」是一種很好的做法。擁有「學生」角色和「導師」角色要好得多,並且只需擁有角色的實例(或列表)(如果使用列表,則爲角色)。 – corsiKa

1
  1. 您可以使用與導師完全相同的信息創建一個新學生並丟棄原始對象。要麼使用複製構造函數Student(Student original)要麼使用Student toStudent()方法這是一種快速和骯髒的方法。

  2. 而不是讓導師直接擴展一個學生,使Tutor具體的數據和行爲爲Decorator的。或者更好的是,使TutorStudent包含所有人的People對象的裝飾器。這是做這件事的正確方法之一。

  3. 充分利用TutorStudentenum TypePeople持有該領域,這是比上面更容易,但不易伸長,這真的取決於教師和學生之間的差異的性質。

1

有沒有將他「轉化」回學生,他是導師,而導師已經是學生的東西。

但是,通用化此對象的訪問可能會有一些價值,因此您只能使用學生方法。在這裏有幾個Java的成語。

1)您可以在代碼中專門使用Student API,但Tutor部分除外。

2)您可以爲您的對象設置一個「toStudent/toTutor」方法,以便它們返回特定於該角色的對象。

//我的偏好 3)您可以使用接口。讓Tutor和Student都是接口,並使用接口實現來構建對象。如果您使用最少的接口引用對象,而不是重量級繼承模式,那麼您的代碼未來可能會更好地擴展。

4

我想,這個尖叫遏制和界面編程。

如何:

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; }; 
} 

這樣一來,你的學生仍然是一個學生來說,即使它移動到導師的位置。當導師任期屆滿時,您只需GC導師記錄。

另一方面,學生記錄仍然可用於中央服務。

相關問題