假设我有一个包含大约10个字段的Application类。在其他一些实用程序类中,我有以下两种方法之一。这两个中哪个最好用? 传递整个应用程序对象,或仅传入实用程序方法所需的内容是否更好?请解释原因。
public printUsernameAndGroup(String username, String group){
sout(username);
sout(group);
}
public printUsernameAndGroup(Application application){
sout(application.username);
sout(application.group);
}
答案 0 :(得分:4)
关于表演,其中两个是相同的。如果您将功能实现为
public printUsernameAndGroup(String username, String group){
sout(username);
sout(group);
}
在调用函数之前,您将访问对象的用户名和组属性。当你将其实现为
时public printUsernameAndGroup(Application application){
sout(application.username);
sout(application.group);
}
您只是传递该对象的引用副本,而不是复制所有10个字段,并再次访问它的两个属性。
但如果你考虑易用性,第二个将更加用户友好。
答案 1 :(得分:2)
如果您只需要两个值,则只传递两个值。但是,如果您需要超过2个字段,或者应用程序对象的所有10个字段,则最好传递对象。
还有一件事,如果你传递的是一个应用程序对象,那么你的函数只能用 来处理应用程序对象,而不是其他任何东西。但在第一种情况下,您可以传递来自不同对象的任何两个字符串以使其工作。例如我假设你正在打印价值或其他什么。
答案 2 :(得分:1)
最好使用这两个?传递整个应用程序对象,或仅传入实用程序方法所需的内容是否更好?请解释原因。?
根据清洁法典(Bob叔叔)。很明显,具有两个或多个参数的函数比一个参数函数更难理解。
例如,writeField(name)
比writeField(output-Stream, name)
更容易理解。
函数的理想参数数量是 零(niladic)。接下来是 one(monadic) 密切关注二(二元)。 三个论点(三元组) 应该尽可能避免。超过三个 (polyadic)需要非常特殊的理由 - 和 然后不应该使用。
Common Monadic Form:将一个参数传递给函数有两个非常常见的原因。你可能
询问有关该论点的问题,如boolean fileExists(“MyFile”)
。或者你可能是
对该论点进行操作,将其转换为其他内容并将其返回。对于
例如,InputStream fileOpen(“MyFile”)
将文件名String转换为
InputStream
返回值。这两种用法是读者在看到函数时所期望的。
二元函数:具有两个参数的函数比单一函数更难理解。例如,writeField(name)
比writeField(output-Stream, name)
更容易理解。
虽然两者的含义都很清楚,但第一个滑过眼睛,很容易沉积它
含义。第二个需要一个短暂的停顿,直到我们学会忽略第一个参数。
当然,这最终会导致问题,因为我们永远不应该忽视任何问题
代码的一部分。我们忽略的部分是错误隐藏的地方。
当然,有时候两个论点是合适的。例如,
Point p = new Point(0,0);
非常合理。笛卡尔点自然需要两个
参数。实际上,我们会非常惊讶地看到new Point(0)
。但是,在这种情况下,两个参数是单个值的有序组件!而output-Stream
和。{
name
既没有自然的凝聚力,也没有自然的顺序。
Triads:带有三个参数的函数比dyads更难理解。该 订购,暂停和忽略的问题增加了一倍多。我建议你这么想 在创建黑社会之前要小心。
例如,考虑assertEquals
的常见重载需要三个arguments:assertEquals(message, expected, actual)
。你有多少次阅读过
message
并认为是expected
?我特意绊倒并停顿了一下
黑社会很多次。事实上,每次看到它时,我会做一个双重拍摄然后学会忽略它
消息。
参数对象(你问过这个):当一个函数似乎需要两个或三个以上的参数时,可能会有一些 那些论点应该包含在他们自己的一类中。例如,考虑一下 以下两个声明之间的差异:
Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
通过从中创建对象来减少参数的数量可能看起来像
作弊,但不是。当变量组一起传递时,方式x
和
y
在上面的示例中,它们可能是值得其名称的概念的一部分
自己的。
Argumen列表:有时我们希望将可变数量的参数传递给函数。考虑一下
例如,String.format
方法:
String.format("%s worked %.2f hours.", name, hours);
如果变量参数的处理方式完全相同,那么就像上面的例子中那样
它们相当于List类型的单个参数。根据这个推理,String.format
是
实际上是二元的。实际上,如下所示String.format
的声明显然是明确的
二进
public String format(String format, Object... args)
因此所有相同的规则都适用。采用变量参数的函数可以是monad, 二元组,甚至是三元组。但给他们提供更多的论据是错误的 这一点。
void monad(Integer... args);
void dyad(String name, Integer... args);
void triad(String name, int count, Integer... args);
简而言之,每个系统都是由程序员设计的特定于域的语言构建的
描述那个系统。函数是该语言的动词,类是名词。
如果您遵循此处的规则,您的功能将会很好并且组织得很好。
但永远不要忘记,你的真正目标是讲述系统的故事,以及功能 你写的需要干净利落地整合成一个清晰准确的语言来帮助你 那个说。
如果我有机会修改您的代码,我将修改如下:
//it's already fine:
public printUsernameAndGroup(String username, String group){
sout(username);
sout(group);
}
//I changed printUsernameAndGroup to printUserInformation and Application to User for more readable
public printUserInformation(User user){
sout(user.username);
sout(user.group);
}
但这只是我对你当前代码的建议。对于整个项目的设计和方法,这取决于你,我希望你能得到你真正需要知道的东西。
答案 3 :(得分:0)
考虑什么是你的功能的正确抽象。它是对整个对象有效还是仅对其中的一部分有效。它可以自然访问整个对象吗?或者它应该可以访问它自己的东西。
一般情况下,尽量保持参数数量的简短'。根据您的编码指南,它可能介于3到8个参数之间。
如果你有一个需要很多参数的方法,那么它表明它做得太多,或者它可能需要一个单独的对象来指示它的功能,并且可能是重构到一个单独的对象的候选者对象
考虑:
rightTurn(int leftwheelPos, int rightweelPos, int newSteeringPos, int speed, int acceleration, int weight, int maximumTurnSize);
VS
rightTurn(Vehicle v);
第二个可能更清楚。但是,还要考虑以下方法:
showSpeedOnDashboard(int speed, DashBoard dashboard) {
dashboard.moveSpeedIndicatorTo(speed/10);
}
VS
showSpeedOnDashboard(Vehicle v) {
v.getDashboard().moveSpeedIndiatorTo(v.getSpeed()/10);
}
这似乎是一样的......但突然之间你的showSpeedonDashboard依赖于车辆。如果该仪表板是通用的并且显示水流的速度怎么办?如果我的仪表板在我的屏幕上,依次显示不同汽车的速度怎么办?
所以,当你几乎什么都不需要的时候,保持简短的事情,不要过分通过整个物品。如果参数太多,可以考虑创建一个可以初始化的值对象(可能使用构建器)。
答案 4 :(得分:0)
您应该注意的一些问题:
80%的String-methods不支持Username或Groupname。
为他们制作简单的课程,例如User
和Group
。
现在方法printUsernameAndGroup
。它不是为广泛使用而设计的,所以如果你只想打印用户名或组名,你必须重复部分代码 - 这个事实违反了DRY原则。
我的解决方案:
Instead of call printUsernameAndGroup call:
sout(application.user);
sout(application.group);
答案 5 :(得分:0)
我的建议是不要盲目地创建类只是因为你必须传递超过7个参数(当然我遵循代码竞争书,其中声明如果参数是> 5-7,你应该创建对象)。
对于例如创建实例,应用100个mutator然后将其作为对象传递应该不是解决方案,因为它在方法中传递100个参数是不好的。这也是代码味道
重温您的设计,看看是否还有其他事情可以做。每次传递参数时,您都不希望最终创建类/对象。有点常识。话虽这么说,如果你确实有一个有效的场景,你必须通过> 5-7参数,做传递对象。
最佳建议,使用 PMD 或 Checkstyle 等工具。当你没有遵循几个标准时,他们将帮助举旗,这些工具基本上被称为源代码分析器
注意:当涉及构造函数时,请阅读本link中提到的构造函数链接。
答案 6 :(得分:0)
既不! :)(我的个人观点,针对您的具体情况)
最佳OO实践是在所有者类中操作数据项,而不是在某些可以神奇地查看所有数据项的外部实用程序类中。这是一种最大限度地打破封装的风格。所有者类应该模拟真实世界(用户)。应用程序类还可以存在,并且可以引用User。 更好:
public class User {
private String username;
private String group;
...
public void printUsernameAndGroup(Writer w) {
w.write(this.username);
w.write(", ");
w.write(this.group);
}
}
public class Application {
private User user;
....
public void printAppDetails(Writer w) {
...
this.user.printUsernameAndGroup(w);
...
}
如果用户详细信息始终包含相同的属性,则可以使用标准toString
方法。更好的是:
public class User {
private String username;
private String group;
...
public String toString(Writer w) {
StringBuffer sb = new StringBuffer(this.username);
sb.append(", ");
sb.append(this.group);
return sb; // implicitly calls sb.toString() to cast
}
}
public class Application {
private User user;
....
public void printAppDetails(Writer w) {
...
w.write(user); // implicitly calls user.toString() to cast
...
}