在我的软件中,我需要根据2个参数确定功能的版本。例如。
Render version 1 -> if (param1 && param2) == true;
Render version 2 -> if (!param1 && !param2) == true;
Render version 3 -> if only param1 == true;
Render version 4 -> if only param2 == true;
因此,为了满足此要求,我编写了一个看起来像这样的代码-
if(param1 && param2) //both are true {
version = 1;
}
else if(!param1 && !param2) //both are false {
version = 2;
}
else if(!param2) //Means param1 is true {
version = 3;
}
else { //Means param2 is true
version = 4;
}
肯定有多种编码方法,但是我尝试了不同的方法后最终确定了此方法,因为这是我能想到的最易读的代码。
但是这段代码绝对不可扩展,因为-
可以使用任何可扩展且可读的方式来编码这些要求吗?
答案 0 :(得分:5)
如果必须枚举所有可能的布尔值组合,将它们转换成数字通常是最简单的:
// param1: F T F T
// param2; F F T T
static final int[] VERSIONS = new int[]{2, 3, 4, 1};
...
version = VERSIONS[(param1 ? 1:0) + (param2 ? 2:0)];
答案 1 :(得分:5)
编辑:
对于可伸缩解决方案,请通过Map
为每个参数组合定义版本:
Map<List<Boolean>, Integer> paramsToVersion = Map.of(
List.of(true, true), 1,
List.of(false, false), 2,
List.of(true, false), 3,
List.of(false, true), 4);
现在找到合适的版本是一个简单的地图查找:
version = paramsToVersion.get(List.of(param1, param2));
从Java 9开始,我初始化地图的方式就起作用了。在Java的旧版本中,它有点罗word,但可能仍然值得一做。即使在Java 9中,如果您有4个或更多参数(对于16个组合),也需要使用Map.ofEntries
,这也比较罗word。
原始答案:
我的口味是嵌套if
/ else
语句,并且只测试一次每个参数:
if (param1) {
if (param2) {
version = 1;
} else {
version = 3;
}
} else {
if (param2) {
version = 4;
} else {
version = 2;
}
}
但是它无法很好地扩展到许多参数。
答案 2 :(得分:4)
我怀疑是否有一种方法可以同时变得更紧凑,可读性和可伸缩性。
您将条件表示为最小化表达式,该表达式紧凑且可能有意义(特别是无关的变量不会使它们混乱)。但是没有可以利用的系统主义。
一个非常系统的替代方案可以是真值表,即所有组合的显式扩展以及相关的真值(或版本号),这在运行时间方面可能非常有效。但是这些变量的大小呈指数形式,而且可读性不强。
恐怕没有免费的午餐。您当前的解决方案非常好。
如果您追求效率(即避免需要顺序求值所有表达式),则可以考虑采用真值表方法,但是可以采用以下方式:
声明一个包含2 ^ n个条目的版本号数组;
使用代码就像编写一样初始化所有表条目;为此,请枚举[0,2 ^ n)中的所有整数并使用其二进制表示形式;
现在进行查询,从n个输入布尔值中形成一个整数索引并查找数组。
使用Olevv的答案,表格将是[2,4,3,1]。查找将类似于(false,true)=> T [01b] = 4。
重要的是,原始表达式集仍然存在于代码中,以供人类阅读。您可以在运行时将其填充到数组的初始化函数中使用它,也可以使用它对表进行硬编码(并将代码保留在注释中;甚至更好的是,将生成硬编码的代码保留在表中)。表格)。
答案 3 :(得分:4)
您的参数组合不过是一个二进制数(如01100
),其中0
表示false
,而1
表示true
。
因此,可以通过使用1和0的所有组合轻松计算您的版本。可能有2个输入参数的组合是:
11
->都是true
10
->第一个是true
,第二个是false
01
->第一个是false
,第二个是true
00
->都是false
因此,借助这些知识,我提出了一个使用“位掩码”(不超过数字)和“位操作”的可扩展性很强的解决方案:
public static int getVersion(boolean... params) {
int length = params.length;
int mask = (1 << length) - 1;
for(int i = 0; i < length; i++) {
if(!params[i]) {
mask &= ~(1 << length - i - 1);
}
}
return mask + 1;
}
最有趣的一行可能是这样:
mask &= ~(1 << length - i - 1);
它一次完成很多事情,我将其拆分。 length - i - 1
部分从右边开始计算“位”在位掩码中的位置(0
,例如在数组中)。
下一部分:1 << (length - i - 1)
将数字1
左移数量。假设我们的位置为3,则操作1 << 2
(2
是第三个位置)的结果将是值100
的二进制数。
~
符号是一个二进制逆,因此所有位都被反转,所有0
都变为1
,所有1
都变为{{1} }。在前面的示例中,0
的倒数为100
。
最后一部分:011
与mask &= n
相同,其中mask = mask & n
是先前计算的值n
。这只不过是二进制AND,因此保留011
和mask
中所有相同的位,并丢弃所有其他位。
总而言之,如果输入参数为n
,那么此行只不过是删除mask
给定位置的“位”。
如果版本号不是从false
到1
连续的,那么像this one这样的版本查找表可能会对您有所帮助。
整个代码只需要在最后一行进行一次调整:
4
您的return VERSIONS[mask];
数组按顺序包含所有版本,但相反。 (VERSIONS
的索引0
是两个参数均为假的位置)
答案 4 :(得分:2)
我本来应该和:
if (param1) {
if (param2) {
} else {
}
} else {
if (param2) {
} else {
}
}
种类重复,但每个条件仅评估一次,您可以轻松找到针对任何特定组合执行的代码。当然,添加第三个参数会使代码加倍。但是,如果有任何无效的组合,则可以省去那些会缩短代码的组合。或者,如果您想为它们抛出异常,则很容易查看您错过了哪种组合。如果IF太长,您可以在方法中显示实际代码:
if (param1) {
if (param2) {
method_12();
} else {
method_1();
}
} else {
if (param2) {
method_2();
} else {
method_none();
}
}
因此,您的整个开关逻辑将承担自身的功能,而任何组合的实际代码都在另一种方法中。当需要使用特定组合的代码时,只需查找适当的方法即可。大型IF迷宫很少被看到,当它出现时,它仅包含IF本身,而没有其他可能使人分心的东西。