我一直在沮丧地试图绕过OOD。我正在尝试构建一个包含三个类的程序 - 一个名为Person,其中包含一个由个人信息组成的构造函数。另一个名为Doctor的类继承了Person类,只是构造一个带有额外字段的对象(大多数字段,即名称,地址将指向person对象),称为专业。我使用另一个类来构建java应用程序来创建,查看和修改person和doctor对象中的字段。
我已经建立了人员和医生课程,你可以在这篇文章的底部找到他们的相关代码。当我尝试创建医生对象时会出现问题,因为我的代码似乎正在创建一个与person对象无关的全新的医生对象。我已经尝试编辑人物对象的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++;
我到底在做什么?为大量的代码道歉 - 我尽我所能地减少了代码,但我不确定问题出在哪里,所以我只能这么做。
人员类
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 :(得分:0)
使用person = getPersonID(personID);
获得的人与使用doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality)
创建的医生完全不同。
仅仅因为他们有相同的,例如firstName等并不意味着对象有任何关系。
您可以通过多种方式解决此问题。例如,你不能创建一个Person,后面跟着Doctor,而只是创建一个Doctor。但是,这并不反映现实生活,因此您可以使用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);
答案 1 :(得分:0)
在设计两个彼此有关系的对象时,有两种常用的模式。
继承。继承是一种强大的工具,但它不是灵丹妙药,它有自己的问题和局限。如果B类与A类的是关系,您应该只使用继承。例如,山地自行车是一辆自行车,所以拥有MountainBike
类{{extend
{{{ 1}}`自行车'。如果你不能说存在“是一种”关系,那就不要使用继承。
组合物。组合也是一个强大的工具,可以说比继承更强大,更脆弱。当B类属于A类属性时(或A类具有 B类)时使用组合。在这种情况下,您将使B类成为A类的实例字段。
在您描述的模型中,医生是人,因此使用继承似乎非常明智。既然我们可以看到您的域模型是您展示的两个类,我也会选择让Doctor扩展Person。
作为一种风格问题,您应该养成在打算从基类覆盖方法时使用@Override
注释的习惯。执行此操作时,编译器将提醒您,否则很难发现错误。您应该使用toString()
对Object
方法(继承自@Override
)进行注释。
当我尝试创建医生对象时出现问题,因为我的代码似乎 创造一个没有关系的全新医生对象 无论如何对人物。
使用
创建Doctor实例时Doctor doc = new Doctor(...);
你得到的对象既是它自己的类型,也是它的父类型,例如。医生是医生,医生是人。以下是合法的:
Person person = new Doctor(...);
您可以将子类中的对象分配给其超类型(或父类)的变量。没有创建新的Person对象,只有Doctor对象(可以将其分配给Person变量,因为医生是一个人)。
这是不允许的:
Doctor doc = new Person(...);
所有医生都是人,但......并非所有人都是医生,所以这项任务会有问题。编译器不允许你这样做。
答案 2 :(得分:0)
创建Doctor
后,它会获得自己的成员变量。这样想:
你有一个Person
,在他那令人敬畏的夹克上有铭牌,地址牌等。现在你交出他Person
的牌照。在此之后,您想要将他推广到Doctor
,但由于Doctor
继承了Person
,他还拥有自己的铭牌,地址等。
他们没有分享它。
所以你想要做的是使用Composition
。
e.g。
public class Doctor(){
private Person person;
private String speciality;
public Doctor(Person person, speciality){
this.person = person;
this.speciality = speciality;
}
}
现在,如果您更改Person
的名称,它还会更新指向该人员的所有Doctors
的名称。
答案 3 :(得分:0)
应该发生什么。医生是一个人,但一个人不是医生。
现在,当您创建Person对象时,您将创建Person类的实例,并将其作为对象放在堆上。
然后从该对象中检索各种字段,并使用它们来初始化Doctor的新实例,并将此新对象放入堆中。这是Doctor类型的一个独特的新对象,它也是Person类型,但它是不您创建的旧Person对象。这是继承。以你期望的方式工作将是灾难性的。
组合不是解决问题的正确方法,因为医生是的人没有拥有的人,这没什么意义。
你可以做的是使用装饰器模式,让Doctor成为一个人可以拥有或不拥有的属性。一个好的教程是this
答案 4 :(得分:0)
看起来你期望继承的行为不会发生。 Doctor对象与单独的Person对象没有某种关系。它医生是人,因此它包含在Person中定义的所有字段,以及Doctor中定义的字段。
new Person()
来创建成员,他们将永远不会成为医生。可能有点偏离主题,你应该重新考虑继承是否是正确的方法。 @Dragondraikk的评论是准确的。在我看来,"是一个"继承测试应该用"替换为应用程序的生命周期"。成为博士是一个人所扮演的时间限制角色。这指向使用构图。这样一个人一旦获得资格就可以成为医生,并且如果他们被罢工就可以恢复成为一个人。在对象的生命周期中更改对象的具体类型绝不是一个好主意。
如果我错误地解释了您的问题,请提前道歉。
答案 5 :(得分:0)
当Doctor对象存储在内存中时,将完成分配 对于超类(Person)中的字段,然后是Doctor类中的字段。
因此,当医生对象存储在内存中时,它不是一整个对象 部分是一个人,部分是医生。
JVM对象知道连接到Doctor对象内存分配的结构是Doctor对象的唯一方法是通过a 标有“类信息的本地指针”的4字节数量。
类型安全转换和instanceof运算符等使用此信息来确定此内存分配所属的类结构 到。
所以确实,关系是继承,如前所述 自医生IS A Person(如果医生有患者然后它是组成)的答案
Bill Venners的这篇文章对这个主题给出了更详细的解释。 http://www.artima.com/designtechniques/initializationP.html
另一个重要的一点是,即使Person在内存被分配给a时仍然无法在Doctor中直接访问私有变量 医生对象有为私有变量分配的内存 清楚地表明整个变量设置为超级和子类 是什么构成了子类。