2015-05-13 155 views
0

我一直在試圖圍繞OOD包裹頭部而感到沮喪。我試圖建立一個有三個類的程序 - 一個叫Person,它有一個由個人信息組成的構造器。另一個名爲Doctor的類繼承了Person類,只是構造一個帶有額外字段(大部分字段,即名稱,地址將指向person對象)稱爲專業的對象。我使用另一個類來構建Java應用程序來創建,查看和修改人員和醫生對象中的字段。從構造函數構造鏈接的Java對象

我已經構建了人員和醫生類,你可以在這篇文章的底部找到他們的相關代碼。當我嘗試創建醫生對象時,會出現問題,因爲我的代碼似乎在創建與人物無關的全新醫生對象。我試圖編輯人物對象的firstName字符串,但醫生對象沒有更新以反映它。它似乎創建了它自己的永久名稱,而不是簡單地指向person對象中定義的名稱。

我通過用戶輸入創建人物對象並使用以下行存儲它們。

 persons[amountPersons] = new Person (firstName, lastName, homeAddress, phoneNumber); 
     amountPersons++; 

一個人一旦對象被創建,用戶可以輸入personNumber創造像這樣

person = getPersonID(personID); 

     int personNumber; 
     String firstName = null; 
     String lastName = null; 
     String homeAddress = null; 
     String phoneNumber = null; 


     firstName = person.firstName; 
     lastName = person.lastName; 
     homeAddress = person.homeAddress; 
     phoneNumber = person.phoneNumber; 
     personNumber = person.personNumber; 

     System.out.print ("Enter speciality of the doctor: "); 
     String speciality = input.nextLine(); 

     doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality); 
     amountDoctors++; 

這到底我做錯了醫生的對象?對大量代碼表示歉意 - 我儘可能地減少了代碼,但我不確定問題出在哪裏,所以我只能這麼做。

Person類

public class Person { 

//Instance Variables 
protected String firstName; 
protected String lastName; 
protected String homeAddress; 
protected String phoneNumber; 
protected int personNumber; 

private static int NumberSystem = 1; 



public Person() 
{ 
firstName = " "; 
lastName = " "; 
homeAddress = " "; 
phoneNumber = " "; 
personNumber = 0; 
} 


public Person (String firstName, String lastName, String homeAddress, String phoneNumber) 
{ 
// Initialize instance variables 
this.firstName = firstName; 
this.lastName = lastName; 
this.homeAddress = homeAddress; 
this.phoneNumber = phoneNumber; 
personNumber = NumberSystem; 
NumberSystem = NumberSystem + 1; 
} 


public String toString() 
{ 
    String p; 
    p = "=================================================" +"\n" + 
     "Identification Number: " + personNumber +"\n" + 
     "Name: " + firstName +"\n" + 
     "Surname: " + lastName +"\n" + 
     "Address: " + homeAddress +"\n" + 
     "Mobile/Telephone: " + phoneNumber +"\n"; 
return p; 

} 

醫生

public class Doctor extends Person{ 

// the aim of Doctor subclass is to simply add a speciality field 
private String speciality; 
int doctorID; 

public Doctor() { 
    doctorID = 0; 
    speciality = "none"; 
} 


public Doctor(String firstName, String lastName, String homeAddress, String phoneNumber, String speciality) { 
    super(firstName, lastName, homeAddress, phoneNumber); 
    this.speciality = speciality; 
    } 


public String toString() 
{ 
    String d; 
    d = "=================================================" +"\n" + 
     "Doctor Number: " + doctorID +"\n" + 
     "Person Number: " + personNumber +"\n" + 
     "Name: " + firstName +"\n" + 
     "Surname: " + lastName +"\n" + 
     "Address: " + homeAddress +"\n" + 
     "Mobile/Telephone: " + phoneNumber +"\n" + 
     "Speciality: " + speciality +"\n"; 
return d; 

} 


} 
+0

它對我來說就像你不尋找繼承,但組成。目前,當你有'Doctor'時,它也是'Person',這意味着你可以在任何可以使用'Person'的地方使用它。儘管如此,它並沒有將其鏈接到任何其他的「Person」對象。要做到這一點,您需要讓'Doctor'擁有'Person'字段,而不是將其作爲子類。 – Dragondraikk

回答

0

稱這有跡象表明,正在設計有兩個對象時會用到兩個常用的模式彼此之間的關係。

  • 繼承。繼承是一個強大的工具,但它不是萬能的,它帶有自身的問題和侷限性。您應該只使用繼承,如果B類有與A類的關係。例如,山地自行車是一輛自行車,所以它是一個明智的類別extend`自行車'。如果你不能說有一個「是」的關係,那麼不要使用繼承。

  • 組成。組合也是一個強大的工具,可以說比繼承更強大,更脆弱。當B類屬於A類屬性時(或者當A類具有B類時)使用組合。在這種情況下,你這是B級A級

的實例字段在你描述的模型,醫生人,所以它看起來非常明智使用繼承。既然我們可以看到你的領域模型是你展示的兩個類,我也會選擇讓Doctor擴展Person。

作爲一種風格,您應該養成習慣於在打算從基類中覆蓋方法時使用@Override註釋。當你這樣做時,編譯器會提醒你否則很難發現錯誤。您應該用@Override註釋toString()方法(從Object繼承)。

的問題,當我嘗試創建醫生對象作爲我的代碼似乎 與無關 任何的人對象創建一個全新的醫生對象時發生。

當您使用

Doctor doc = new Doctor(...); 

,你得到的是一個對象實例的醫生其本身的類型以及其父母的類型,如。醫生醫生,而醫生人。以下是合法的:

Person person = new Doctor(...); 

你被允許從一個子類分配對象到它的超類型(或父)的變量。沒有新的Person對象被創建,只有Doctor對象(因爲醫生是一個人可以被分配給Person變量)。

這是不允許的:

Doctor doc = new Person(...); 

所有醫生的人,但是......不是所有的人都是醫生所以這個任務將是有問題的。編譯器不會讓你這樣做。

+0

感謝您對兩者之間的解釋 - 我必須在某些時候對繼承和構圖產生混淆/混淆。我想我必須讀一些關於這個主題的內容,然後試着重新思考它。但是,我有最後一個可能的問題。讓我們忽略我原來的問題,在那裏我將組合設計技術與繼承混淆起來。你會說醫生和人類以及我初始化這些類的對象的方式是繼承的好例子嗎? – Stylw

+0

您的對象模型沒有任何問題。你應該總是設法設計不可變的值類。我會讓這兩個類中的實例字段成爲final(除非不能;必須符合JavaBean協議的值對象不能有最終字段)。最後,構造函數有很多參數。如果您打算長時間維護這些類,那麼這些類看起來非常適合Builder模式。 – scottb

0

person = getPersonID(personID);獲得的人是完全不同的對象給您doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality)創建醫生。

只因爲他們有相同的例如firstName等,並不意味着對象有任何關係。

您可以通過幾種方法解決這個問題。例如,你不能創建一個人,其次是醫生,而不是創建一個醫生。但是,這並不反映現實生活,所以您可以用Doctor替換您存儲在陣列中的人員。

Person[] people = // however you initialise it; 
Doctor[] doctors // however you initialise it; 

既然醫生也是一個人,你可以簡單地說people[i] = doctor。基於上面的代碼,它可能被包裹在一個方法調用是這樣的:

// I'm assuming personID is an int, but you may need to adapt this 
private void replacePerson(int personID, 
          Person person) { 
    int index = // get index of personID from the array 
    people[index] = person; 
} 

Doctor doctor = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality); 
doctors[amountDoctors] = doctor; 
amountDoctors++; 
replacePerson(personID, doctor); 
0

一旦你創建了一個Doctor它會得到他自己的成員變量。這樣想:

你有一個Person它有一個銘牌,地址等他的真棒夾克。現在你交出這個Person他的盤子。之後你想將他升爲Doctor,但由於Doctor繼承Person他還有自己的很多自己的銘牌,地址牌等。 他們沒有分享它。

所以你想要做的就是使用Composition。 例如

public class Doctor(){ 
    private Person person; 
    private String speciality; 
    public Doctor(Person person, speciality){ 
    this.person = person; 
    this.speciality = speciality; 
    } 
} 

現在,如果你改變了Person的名字,它也將更新其指出該人所有Doctors的名稱。

0

發生什麼事情是應該發生的。醫生是一個人,但一個人不是醫生。

現在,當您創建Person對象時,您將創建Person類的一個實例,並將其作爲對象放置在堆上。

然後,您從該對象中檢索各個字段,並使用它們初始化Doctor的NEW實例,並將此新對象放置到堆中。這是Doctor類型的一個明顯的新對象,它也是Person類型的,但它是而不是您創建的舊Person對象。這是繼承。以您期望的方式工作將會是災難性的。

成分是不是你的問題的解決方案,因爲它沒有什麼意義,因爲醫生人不人。

你可以做的是使用修飾器模式,並有醫生是一個人可以或不可以有的屬性。一個好的教程將是this

0

它看起來像你期待的行爲繼承只是不會發生。 Doctor對象與單獨的Person對象沒有某種關係。 It Doctor Person,因此它包含Person中定義的所有字段以及Doctor中定義的字段。

  1. 你的person []數組可以存儲Person類和Doctor類。但是,如果您使用new Person()創建成員,他們將永遠不會成爲醫生。
  2. 目前還不清楚爲什麼你有一組人和醫生陣列。
  3. 繼承是編譯時的概念。這聽起來像在運行時期間,您希望爲醫生提供Person記錄和Doctor記錄。您將只有一個Doctor記錄,由於繼承將包含所有Person字段。

可能是一個小題目,你應該重新考慮繼承是否是正確的方法。 @ Dragondraikk的評論是準確的。在我看來,對於繼承的「是」測試應該被「是對應用程序的生命」所取代。成爲一名醫生是一個人扮演的時間限制角色。這指向使用組合。這樣一旦一個人符合條件,一個人就可以成爲一名醫生,如果他們被取消,他可以恢復成爲一個人。在其生命週期中更改對象的具體類型絕不是一個好主意。

如果我錯誤地解釋了您的問題,請事先道歉。

0

當Doctor對象被存儲在內存中時,將爲超類(Person)中的字段和Doctor類中的字段分配 。

所以當醫生對象被存儲在內存中時,它是一個整體對象而不是 部分是一個人,一部分是醫生。

JVM對象知道連接到Doctor對象內存分配的結構是Doctor對象的唯一方法是通過一個標記爲「指向類信息的本機指針」的4字節數量的 。

類型安全鑄造和instanceof操作符等使用此信息來確定此內存分配屬於哪種類結構 到。

所以是確實的關係是繼承的,如前面 答案中提到,因爲醫生是一個人(如果醫生有患者則是組成)

本文由比爾給出的話題更詳細的解釋.. http://www.artima.com/designtechniques/initializationP.html

一個更重要的一點是,即使人有私有變量還不是當內存分配給一個 醫生對象有分配給私有變量存儲其中 清楚地表明,在醫生直接訪問該爲超級和子級 設置的整個變量在一起構成子類。