我的问题是:使用 stdin
初始化的字段编写Java类构造函数的最佳方法是什么?
例如,假设我有一个 Employee
类,看起来像:
Public class Employee {
private int empID;
private String empName;
private List<Role> empRoles;
{....}
}
我可以为这堂课写下所有的二传手和门手 . 当然, 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();
}
然后:
-
我可以在覆盖默认构造函数的构造函数中使用这样的setter .
-
这是编写此类构造函数的最佳方法吗?
-
将我在每个setter中创建的
Scanner
对象移动到构造函数并将其作为setter的参数更好
例如:
public void setEmpName(Scanner s) {
...
this.empName = s.next();
}
如您所见,这可能是一个设计问题,而不仅仅是“编码” .
非常感谢您的帮助 .
3 回答
实际上,你 don't 依赖于一种使用特定构造函数填充对象字段的方法,但是没有arg构造函数 .
您确实选择了一个setter方法来在调用
new Employe()
之后填充Employee
实例的字段 .但是这种setter方法很复杂,因为你混合了太多的责任:获取用户输入和设置对象的状态 .
不,这没有任何意义:构造函数和setter是两种不同的方式,你不能用另一种方式覆盖它们 .
然而,您可以通过依赖
Scanner
实例来获取用户输入来调用构造函数中的setter,但与实际的setter方法类似,这似乎是一种尴尬的方法,因为它给构造函数带来了太多的责任 .使用填充所有字段的构造函数,即:
如果您的对象在创建后被设计为不可变的,那么这是有意义的 .
在您的实际情况中,如果您的对象不是使用构造函数设置为不可变的,或者setter是有效的,但无论如何,您应该提供setter .
因此,要回答您的问题,您应该分离职责(获取用户输入和设置对象状态),并根据您对
Employee
实例的要求使用setter或构造函数方法:要么
我认为您可能会将用户输入/输出与程序模型混淆 . 这里的关键是你应该把两者完全分开 . Employee类应该完全了解使用什么类型的UI或I / O来使用它,因为这样可以在GUI,控制台程序或其他任何需要的地方使用它 .
因此,您的Employee构造函数应该只接收创建Employee对象所需的数据,无论其来源如何,并且对于您的字段getter也是如此 .
所以你的getter看起来就像你发布的一样,而是更简单,更“哑”或“无知”的用户I / O(Scanner,System.in等)
其他领域也一样 .
所有的I / O东西 - Scanner类等都在你的驱动程序类中的其他地方 .
旁注:当您使用基于
System.in
的扫描仪时,您的程序应该创建一个且只有一个这样的野兽,在需要时创建它,然后仅在程序完全使用它时关闭并处理它 . 否则,您可能会过早关闭连接而破坏系统输入 . 这是在您创建多个Scanner对象时不使用您建议的代码的另一个原因 .例如....
然后你可以在其他地方使用它:
已经有两个好的答案,但我想再给你一个问题的解决方案 . 正如@davidxx已经说过,如果你的对象应该是不可变的,那么所有参数构造函数都是一个更好的方法而不是setter,但让我们考虑一下你有更多字段的情况 . 例如,您的员工有薪水,经验和其他 . 你的构造函数开始看起来像这样:
正如您所看到的,构造函数开始变得太长 . 这称为伸缩构造器 . 让我们考虑一下您的员工有2-3个必填字段而其他字段不需要的情况 . 要创建此对象,您必须编写如下代码:
这是有问题的,因为:
将null传递给函数可能会引起很多麻烦 .
此代码不太可读 .
您可以添加只接收所需字段的构造函数,但每次需要传递不同的参数组合时,您都必须添加新的构造函数(打破Open-Closed原则) . 这种情况的解决方案是使用构建器模式:
然后你可以像这样创建你的对象: