我有两个类,Person
和Employee
。 Employee
扩展Person
.
我有一个从存储中读取Person
的方法,并且正在编写读取Employee
的方法。
我想重用我为Person
读取与Employee
相同的属性的方法,而无需复制粘贴代码,但似乎找不到一种方法。
public Person getPersonFromStorage() {
Person person = new Person();
// ... logic
return person;
}
public Employee getEmployeeFromStorage() {
Employee employee = new Employee();
// ... logic for employee-specific fields
// I want to read the fields inherited from Person here
return employee;
}
我无法从getPersonFromStorage
中转换检索到的Person
,因为它不是Employee
。可能是,因为它也不是另一种亚型,但事实并非如此。
我可以执行以下操作:
public Person getPersonFromStorage(Person person) {
if(person==null) { person = new Person(); }
// ... logic
return person;
}
public Employee getEmployeeFromStorage() {
Employee employee = (Employee) getPersonFromStorage(new Employee());
// ... logic for employee-specific fields
return employee;
}
但如果可以的话,我想避免这种复杂性。我有一种感觉,我忽略了一些基本的东西。有没有更好的方法来解决这个问题?
只是提供我通常在这种情况下使用的不同架构。如果你谈论的是"来自存储",对我来说,这意味着某种持久的结构。文本文件、数据库等对于以下示例,假设您的值位于文本文件中。
假设文件employees.txt
,其中包含一个员工:
// Dave's person details.
Dave
Manchester
32
// Dave's employee details
Assassin
Mostly North Korea.
然后你有一个类Person
,看起来有点像这样:
public class Person
{
private String name;
private String location;
private int age;
public Person(String name, String location, int age)
{
// blah blah blah.
}
}
类Employee
如下所示:
public class Employee extends Person
{
private String jobTitle;
private String area;
public Employee() {
// etc.
}
}
在 Person
类中,可以创建一个构造函数,旨在读取Person
的参数。像这样:
public Person(Scanner file)
{
this.name = file.nextLine();
this.location = file.nextLine();
this.age = file.nextInt();
file.nextLine(); // Make sure you're pointing at the new line!
}
在 Employee
类中,您可以创建一个构造函数,旨在读取员工的参数,同时调用它的超类来处理其他值。
public Employee(Scanner file)
{
super(file);
this.jobTitle = scanner.nextLine();
this.area = scanner.nextLine();
}
然后你所要做的就是调用它:
Scanner s = new Scanner("employees.txt");
Person p = new Employee(s);
或者使其更紧凑:
Person p = new Employee(new Scanner("employees.txt"));
这将去解析文件,并返回一个对象,同时在需要数据的类中包装实际读取文件的所有逻辑。
不是文本文件?
好吧,这并不重要。重要的是将对象传递到调用链上,这些方法正在执行该特定类需要执行的操作,然后传递该对象。如果是database row
,原理完全一样。
你的第二个代码示例是要走的路,除了你甚至不需要null
检查行。只需传入您在其他地方实例化的非空Person
即可。
为了获得更好的抽象,请查看是否可以将Person
变成abstract
类。
更优雅的方法是重载Employee
构造函数,以便能够从父实例Person
创建Employee
实例。
public Employee getEmployeeFromStorage() {
Employee employee = new Employee(getPersonFromStorage());
// ... logic for employee-specific fields
return employee;
}
您可以使用受保护的工厂方法。
protected Person createNewInstance() { return new Person(); }
并在 getPersonFromStorage(( 方法中使用它。然后,子类将重写此方法,从而将返回类型更改为 Employee,然后可以像第二个示例中一样使用它。
public class Person {
public Person getPersonFromStorage() {
Person person = createNewInstance();
// ... logic
return person;
}
protected Person createNewInstance() {
return new Person();
}
}
public class Employee extends Person {
public Employee getEmployeeFromStorage() {
Employee employee = (Employee) getPersonFromStorage();
// ... logic for employee-specific fields
return employee;
}
protected Person createNewInstance() {
return new Employee();
}
}
或者,您也可以基于人员创建员工构造函数
public class Employee extends Person {
public Employee(Person person) {
super();
// copy all fields from person
}
public static Employee getEmployeeFromStorage() {
Employee employee = new Employee(getPersonFromStorage());
// ... logic for employee-specific fields
return employee;
}
}
我还向方法添加了静态,假设您打算创建与现有对象没有直接关系的新实例。这不适用于第一个变体。