假设我有以下
Class A {
Foo getFoo();
Bar getBar();
Baz getBaz();
}
我需要定义一个使用一个对象的doStuff
,Foo
,Bar
并执行某些操作的函数Baz
我在实现doStuff
的哪种方法更好(假设将doStuff
放在类A
中不合适)
方法A
void doStuff(Foo foo, Bar bar, Baz baz)
{
//some operation
}
或
方法B
void doStuff(A a)
{
Foo foo = a.getFoo();
Bar bar = a.getBar();
Baz baz = a.getBaz();
//some operation
}
据我所知, (+专业, - 缺点)
方法A
+确切地说明doStuff()
参数
- 易受长参数列表的影响,更容易受到用户错误的影响
方法B
+简单易用的方法
+似乎更具可扩展性(?)
- 对课程A
任何人都可以分享对这两种方法的利弊的额外见解吗?
答案 0 :(得分:23)
方法A(裸参数)总是具有
的优点方法B(Parameter Object)具有优势
参数对象引入了一个新的依赖关系,调用者和被调用者依赖它并不是一个缺点,因为它是一个没有自己依赖的简单类。
因此,参数对象是
答案 1 :(得分:5)
Parameter Object
确实提供了一种很好的方法来封装related
参数,以减少任何方法或构造函数的总参数计数。
应该非常小心地确保参数对象确实包含真正相关的参数。
实际上,根据您正在处理的parameter types
,有多种方法可以解决此问题。
如果您正在处理一般类型的参数,例如多个String
或Int
,并且客户端有可能实际传递错误的参数序列,那么它通常更有意义创建custom types
即。使用可能的值创建enum
。这可以为您的参数提供良好的编译时检查。
它们的另一个好用途是你可以将它们用于return
来自函数的复杂值。请参阅here。
我需要花费很多时间的另一种方法是检查并查看doStuff
方法完成的工作是否可以分解为具有较少依赖性的简单方法。
主要是我尝试遵循Bob Martin建议的最多三个参数。嗯,他实际上说它应该大多不超过一个! 任何增加都应该有正当理由。 请参阅这本优秀的书:Clean Code
答案 2 :(得分:1)
David和Som的答案都有很多值得考虑的信息。我将添加以下内容:
与许多设计模式一样,要做什么的决定取决于选择之间的连续性,各有利弊。并非总是有一个正确的答案-往往取决于您想享受哪些优点,以及您愿意冒险哪些缺点。
以我的经验,当您具有总是一起旅行的相关值时,转到DTO会很有帮助。大卫很好地描述了这种方法的优点。我看到的这种方法的另一个缺点是,随着DTO的增长,您可能会给方法添加不必要的依赖关系。
例如,方法A,B,C和D带有Foo,Bar和Baz,因此将这些参数组合到DTO中非常好。然后方法A和B需要使用Quux-您是否将Quux添加到DTO中以迫使C和D承担未使用的依赖关系?测试C和D时,您会为Quux传递什么值?当新开发人员使用方法C和D时,Quux的存在会引起混乱吗?在比较方法A和方法C时,是否清楚应该如何定义Quux?
当所有方法最初都需要Foo,Bar和Baz,但是某些方法不再需要这些值时,会出现类似情况。
我观察到一种经验,一个团队将DTO传递给另一团队,并付出巨大的努力来正确填充和同步该DTO中的信息,而实际上所需的只是一个可以传递的值。琐碎的。
除非值总是在一起,否则您可能会产生混乱,增加测试负担和额外的开发工作。如果这些值始终在一起,则DTO可以提供清晰度,减少重复,简化一致性等。
答案 3 :(得分:0)
请考虑具有地址和 CurrentInvoice 的客户。哪个更正确-
SendInvoiceToAddress(Invoice invoice, Address adress);
或
SendInvoiceToAddress(Customer customer);
我都认为。或换种说法-确实取决于您的应用。
如果每张发票(按定义)属于单个客户,那是一回事。这意味着您的方法存在于CustomerInvoiceSender类(或诸如此类)内。这完全属于客户领域。您想每月发送该月的发票(别无其他)。
如果您想向多个地址发送多张发票(出于任何目的,不一定非要给客户),那么那就完全不一样了。它也可能存在于InvoiceSender类中(或类似的东西)。它也与客户域无关。在这种情况下,客户只是发货的一小盒发票。还值得注意的是,在这种情况下,您可能需要接口而不是具体的,因为客户的发票,并且说公司的发票可能是两个截然不同的类,只是碰巧共享一个公共接口(在这种情况下为“几个属性”)。