当前位置:  开发笔记 > 编程语言 > 正文

"太多参数"警告的解决方案

如何解决《"太多参数"警告的解决方案》经验,为你挑选了3个好方法。

在我的一些方法中,存在太多参数,并且很难维护和读取源代码.有时候我担心的问题是" 他们是否以适当的顺序传递了适当的价值? "

我使用Checkstyle作为我的Eclipse插件,它为我提供了超过7个参数的警告.

我不确定它可能只是一个编码标准,我不关心它.但是当通过视图,服务dao传递许多参数时,我注意到它很难阅读并且以后很难修改.

所以,我试图通过这些参数...

    一些对象豆类.但这给了我另一个问题,因为我的参数不能得到任何保证(不确定它们是否存在).

    HashMap类型参数.但这可能会迫使我检查一些验证并尝试匹配方法调用方面的密钥.

以上两种方法也可能会丢失编译时错误检查.有没有减少参数计数的建议?



1> Mark Phillip..:

传递HashMap是非类型化脚本语言中的常见做法,但在Java中却是一种不好的做法.它击败了强类型的优势,这是您在Java中获得生产力的一部分.换句话说,Java编译器将无法帮助您在开发过程中发现错误,并且您更有可能在运行时捕获它们.

如果您传递的参数在概念上是相关的,那么您可以在提及时将它们分组到适当的对象中.例如,如果您传递诸如firstName,lastName,dateOfBirth等参数,则可以传递具有这些属性的Person对象.这使用OO使您的设计更容易思考和维护.

如果我理解你对此的意思:"但是这给我带来了另一个麻烦,因为我的参数不能得到任何保证(不确定是否包含)",你可以强制执行你的Person或者等对象所需的保证.实例化.一种方法是使用不可变的Person(等)对象:没有setter,而是通过构造函数传递所有params.如果它们不正确,则抛出IllegalArgumentException.

祝好运!


很高兴我的回答很有用.请接受答案,如果它是最适合您的答案.谢谢!

2> Diunuge..:

有一些技术可以减少参数的数量;

    使用最小化的方法(将方法分解为多个方法,每个方法只需要一部分参数)

    使用实用程序类(帮助程序类)来保存参数组(通常是静态成员类)

    使Builder模式从对象构造适应方法调用.

    尝试使用更好的架构设计减少单独包之间的数据流.

参考一些标准的java书;

Java:如何编程

首先是Java

有效的Java

还尝试学习设计模式,它作为最佳编码实践非常有用.

首先设计模式


对不起,但我想我解释了你的需要.如果你正在注意,1.使用最小化的方法; 您可以将验证与普通类分开维护为单独的.2.使用实用程序类; 当数据流更频繁地发生时,您可以使用辅助实用程序类来满足所需的数据需求,并且还可以在其中使用辅助函数(参数转换,...​​(可能是验证)).如果您告诉确切的问题以及您需要的详细程度,我们肯定会有所帮助.
我指出了这些书籍,您可以在其中找到更多有关此内容的详细信息,因为即使在这些建议之后您也需要确切知道如何实施它们,这些答案无法提供您需要的所有详细信息.例如:有效的Java,第7章,第40项:解释它.

3> Przemek Pokr..:

在我提出我的提议之前,让我先谈谈提出的建议.我冒昧地跳过"臭"解决方案--HashMap和bean,因为你可以清楚地看到它们的缺点.

小心

    盲目地使用辅助类来保存参数组.当团队凝聚力时(例如Mark Phillips的回答),他们可以真正发光,但是否则会导致问题(基本上就像打字的HashMap一样).我怀疑它们是否适用于将7个参数从视图传递到DAO层的问题.

    当它们有意义时,最小化的方法也很棒(如在Effective Java book中的List示例中).我很少看到他们这样做的地方,所以我怀疑他们会解决你的问题.

    Builder模式通常非常干净,但它只解决了一层的问题 - 它没有告诉你如何进一步传递参数.当你从视图中获得一个参数,这在DAO中是必需的,那么Builder只会膨胀你的代码,你仍然需要传递参数.

在我最终提出解决方案之前,让我挑战一个常见的隐含假设,即所有数据都需要以方法参数的形式通过堆栈传递.只有将处理对象应用于应用程序或会话范围时,才会出现这种情况.在请求处理开始时创建所有相关对象时,约束消失.然后,您可以使用对象的构造函数仅向其传递必要的信息.

最佳方式:使用请求生命周期的对象

在某种程度上,这类似于方法对象或命令模式.

为了应用此解决方案,您需要更改系统的入口点 - 通常这是某个视图层对象中的方法.让它负责两件事:

请求对象图创建

调用对象图root的执行/运行方法

第一步至关重要.这是您从每个层构建请求范围对象的位置:视图,服务和DAO.对于每个对象,您只需将所需数据传递给其构造函数(例如,如果仅在DAO中需要参数"userIP" - 例如,用于审核DB访问,则仅将其传递给DAO请求对象).请求对象还需要对其协作者的引用(如需要DAO的服务) - 相应地通过构造函数传递它们.

第二步:当您设置对象图时,只需在第一个上调用execute/run方法(通常是视图层中的对象).

/** The example (in Scala) shows how your app's entry point could look like.
 *  The presented method belongs to an app-scoped view-layer object.      
 */
def delete(itemId: Id, userIP: IPAddress) {
  // Note, that only RepositoryHelperReq class is interested in the 
  // "itemId" and "userIP" parameters
  val repoReq = MainRepositoryReq(RepositoryHelperReq(itemId, userIP))
  val serviceReq = MainServiceReq(ServiceHelperReq(repoReq))
  val viewReq = MainViewReq(ViewHelperReq(serviceReq))

  viewReq.execute()
}

现在让我回应一些对这种模式的预期批评.

批评反驳

    有人会说,性能会受到影响,因为堆上会有更多的对象来进行垃圾收集.我会问那些测量,因为通常它不是对象分配,而是成本性能,而是对象保留(参见Simon Ritter的最后一个演示).

    有些人会询问应用程序或会话范围的数据,例如数据源或购物篮对象.这些对象仍然可以使用 - 您只需将它们注入到请求范围的对象中.

    有些人会批评依赖结构,认为视图应仅依赖于服务而不依赖于DAO.这是有效的评论,只需注意,在经典的webapps中,你仍然有一个中心位置,这取决于所使用的每一层(通常被称为"世界末日").有时它是web.xml,有时它是Spring应用程序上下文或Guice模块.如果您关心正确的依赖关系,我建议您将所有工厂逻辑放在这样的位置,让它实现一些View-layer接口并注入视图.这样你的整个依赖结构将保持干净和模块化.

    有人会说,流行的DI框架(主要是Spring)支持这种模式非常糟糕.这是真的,你需要使用一个像样的DI库(Guice,Dagger for Java或Macwire,如果你喜欢Scala)或准备对抗Spring以便做到正确.

好处

    没有长参数列表的气味

    没有不连贯的"请求上下文"对象(MagicContainer反模式)

    没有"印章" - 耦合 - 中间层不需要依赖于传递的参数,因此它们可以独立发布,更可测试和更清洁

    数据仅在需要时使用 - 更容易测试,更少模拟

    即使在其他方法失败的情况下也可以使用,例如当您没有内聚的ParameterObject来提取时,或者当您无法轻松地将方法拆分为最小的正交方法时

积分

MiškoHevery在他的优秀博客文章" 如何使用Servlet完成所有错误"中精确地确定了管理对象生命周期(请参阅"更常见的违规"片段).我想感谢他的帖子,因为很难在其他来源找到关于这个具体问题的准确指导.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有