2015-05-13 150 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

一个更重要的一点是,即使人有私有变量还不是当内存分配给一个 医生对象有分配给私有变量存储其中 清楚地表明,在医生直接访问该为超级和子级 设置的整个变量在一起构成子类。