2

我有两个班,PersonEmployeeEmployee延伸Person

我有一个Person从存储中读取 a 的方法,并且正在编写读取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;
}

我无法转换从 检索PersongetPersonFromStorage内容,因为它不是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;
}

但如果可以的话,我想避免这种复杂性。我觉得我忽略了一些基本的东西。有没有更好的方法来解决这个问题?

4

4 回答 4

1

您的第二个代码示例是要走的路,除了您甚至不需要null检查行。Person只需传入您在其他地方实例化的非空值。

为了更好的抽象,看看你是否可以做成Person一个abstract类。

于 2013-10-07T15:10:23.257 回答
1

更优雅的方法是重载Employee构造函数以便能够Employee从父实例创建Person实例。

public Employee getEmployeeFromStorage() {
    Employee employee = new Employee(getPersonFromStorage());
    // ... logic for employee-specific fields
    return employee;
}
于 2013-10-07T15:16:54.403 回答
1

只是提供我通常在这种情况下使用的不同架构。如果您在谈论“来自存储”,对我来说这意味着某种持久结构。文本文件、数据库等。对于以下示例,假设您在文本文件中有值。

假设一个文件employees.txt,其中包含一名员工:

// Dave's person details.
Dave
Manchester
32
// Dave's employee details
Assassin
Mostly North Korea.

然后你有一个 class 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类中,您可以创建一个构造函数,用于读取 a 的参数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"));

这将解析文件,并返回一个对象,同时将所有用于实际读取文件的逻辑封装在需要数据的类中。

不是文本文件?

嗯,这不是很重要。重要的是只是将一个对象传递到调用链上,这些方法正在执行该特定类需要做的事情,然后传递该对象。如果是a database row,则原理完全相同。

于 2013-10-07T15:25:53.130 回答
0

您可以使用受保护的工厂方法。

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

或者,您也可以基于 Person 创建一个 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;
    }
}

我还在方法中添加了静态,假设您打算创建与现有对象没有直接关系的新实例。这不适用于第一个变体。

于 2013-10-07T15:37:15.900 回答