让我们想象一个简单的结构:
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_first: {
// some code
}
break;
case R.id.btn_second: {
// some code
}
break;
case R.id.btn_third: {
// some code
}
break;
// and so on
}
}
这是一段处理不同按钮点击的简单代码。但随着按钮数量的增加 - switch
块的圈复杂度随之增长。是否有另一种方法来表示此代码构造以减少onClick()
方法的圈复杂度?提前致谢。
public void onClick(View view) {
for (ClickHandler handler : allHandlers()) {
if (handler.supports(view.getId())) {
handler.onClick(view);
}
}
}
interface ClickHandler {
boolean supports(int viewId);
void onClick(View view);
}
为每个分支实现ClickHandler
并让allHandlers()
构建它们的列表。
这是我在早期版本的GWT(Google Web Toolkit)中遇到的问题之一。 GWT是谷歌的答案,为JAVA开发人员提供了一种使用JAVA编写JavaScript代码的方法。
我们开始使用单个匿名内部类来处理网页上的每个事件/元素。当你没有很多元素时,它工作得很好,这对于网页来说是不现实的。因此,随着元素数量的增加,它变得无法管理和混乱。然后我们很快就遇到了你提出的同一个问题。谷歌在更高版本的GWT中使用事件总线解决了这个问题。
这是怎么解决的?他们创建了一个模式,您可以将条件从一个级别抽象到事件总线,并让它调用正确的处理程序。
但是,回到你的javascript问题,这是一个很好的,简单的解释模式,Handling events for many elements
实际上,在我的想法中,你想要做的是完全避免圈复杂度模式,就像我通过事件总线或事件处理程序或映射抽象一个级别一样,最终调用一个函数来避免代码重复并用另一个解决这个问题图案。
我宁愿创建更多的小函数,因此使代码更像组件,而不是让if / else模式继续自我复制。我发现,一旦你沿着那条路走下去,模式没有尽头,你将继续被迫添加更多的if / else语句,直到你用更好的解决方案重构代码。
我记得在JAVA代码中看到了同样的事情,他们正在训练COBOL开发人员学习JAVA以及那些使他们的程序思维不断陷入这种模式的人。我曾经看过一个带有26个条件的switch语句,检查单个类型的条件。
以下是Cyclomatic Complexity Refactoring Tips的一些很好的技巧,有很好的代码示例。
它是可能的(例如带有执行程序或某些东西的hashmap),但在我看来它会使代码质量变差。低圈复杂度对于高质量代码是有利的,但最终目标仍然应该是高质量和可维护的代码,而不是低的圈复杂度。