具有最终用户馈送字段的类的Java构造函数

Has*_*hin 3 java constructor design-patterns

我的问题是:使用通过初始化的字段编写Java类构造函数的最佳方法是什么stdin

例如,假设我有一个Employee类似于以下的类:

Public class Employee {
    private int empID;
    private String empName;
    private List<Role> empRoles;
    {....}
}
Run Code Online (Sandbox Code Playgroud)

我可以为这堂课写下所有的设定者和吸气剂.当然,Role该类将拥有自己的文件.

还假设我为前两个字段创建了我的setter,如下所示,以便让最终用户初始化字段:

public void setEmpID() {
    System.out.println("Please enter the employee ID");
    Scanner s = new Scanner (System.in);
    this.empID = s.nextInt();

public void setEmpName() {
    System.out.println("Please enter the employee name");
    Scanner s = new Scanner (System.in);
    this.empName = s.next();
}
Run Code Online (Sandbox Code Playgroud)

然后:

  1. 我可以在覆盖默认构造函数的构造函数中使用此类setter.
  2. 这是编写此类构造函数的最佳方法吗?
  3. Scanner我在每个setter中创建的对象移动到构造函数并将其作为setter的参数更好

例如:

public void setEmpName(Scanner s) {
    ...
    this.empName = s.next();
}
Run Code Online (Sandbox Code Playgroud)

如您所见,这可能是一个设计问题,而不仅仅是"编码".

非常感谢您的帮助.

Don*_*ter 5

我认为您可能会将用户输入/输出与程序模型混淆.这里的关键是你应该把两者完全分开.Employee类应该完全知道使用它的UI或I/O的类型,因为这样可以在GUI,控制台程序或其他任何需要的地方使用它.

因此,您的Employee构造函数应该只接收创建Employee对象所需的数据,无论其来源如何,并且对于您的字段getter也是如此.

因此,你的getter看起来就像你发布的一样,而是更加简单,更加"愚蠢"或"无知"的用户I/O(Scanner,System.in等)

public void getEmpID (int empID) {
    this.empID = empID;
}
Run Code Online (Sandbox Code Playgroud)

其他领域也一样.

所有的I/O东西 - Scanner类等都在驱动程序类的其他地方.

旁注:当您使用基于System.in程序的扫描程序时,应创建一个且只有一个这样的野兽,在需要时创建它,然后仅在程序完全使用它时关闭并处理它.否则,您可能会因过早关闭连接而破坏系统输入.这是在您创建多个Scanner对象时不使用您提议的代码的另一个原因.

例如....

import java.util.ArrayList;
import java.util.List;

public class Employee {
    private int empID;
    private String empName;
    private List<Role> empRoles;

    public Employee(int empID, String empName) {
        super();
        this.empID = empID;
        this.empName = empName;
        empRoles = new ArrayList<>();
    }

    public int getEmpID() {
        return empID;
    }

    public void setEmpID(int empID) {
        this.empID = empID;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public List<Role> getEmpRoles() {
        return empRoles;
    }

    public boolean addEmpRole(Role role) {
        return empRoles.add(role);
    }

    public boolean removeEmpRole(Role role) {
        return empRoles.remove(role);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后你可以在其他地方使用它:

import java.util.Scanner;

public class TestEmployee {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        System.out.print("Enter employee ID: ");
        int empID = scan.nextInt();
        scan.nextLine();  // handle dangling end of line token

        System.out.print("Enter employee Name: ");
        String empName = scan.nextLine();
        Employee employee = new Employee(empID, empName);       

        // if we are **totally** done with the Scanner, now we may close it
        scan.close();
    }
}
Run Code Online (Sandbox Code Playgroud)


dav*_*xxx 5

实际上,您依赖于使用特定构造函数填充对象字段的方法,而是依赖于无参数构造函数.
您确实选择了一个setter方法来Employee在调用后填充实例的字段new Employe().
但是这种setter方法很复杂,因为你混合了太多的责任:获取用户输入和设置对象的状态.

我可以在覆盖默认构造函数的构造函数中使用此类setter.

不,这没有任何意义:构造函数和setter是两种不同的方式,你不能用另一种方式覆盖它们.
但是,您可以通过依赖Scanner实例来接受用户输入来调用构造函数中的setter,但与实际的setter方法类似,这似乎是一种尴尬的方法,因为它给构造函数带来了太多的责任.

这是编写此类构造函数的最佳方法吗?

使用填充所有字段的构造函数,即:

Employee emp = new Employe(id, name, roles)
Run Code Online (Sandbox Code Playgroud)

如果您的对象在创建后被设计为不可变的,那么这是有意义的.

在您的实际情况中,如果您的对象不是使用构造函数设置为不可变的,或者setter是有效的,但无论如何,您应该提供setter.


因此,要回答您的问题,您应该分离职责(获取用户输入和设置对象状态),并根据您对以下实例的要求使用setter或构造函数方法Employee:

Employee emp = new Employe(id, name, roles)
Run Code Online (Sandbox Code Playgroud)

要么

Employee emp = new Employe();
emp.setId(...);
emp.setName(...);
emp.setRoles(...);
Run Code Online (Sandbox Code Playgroud)