Java 使用多个默认值从缓存中提取时的代码气味?
我们有一个包含4列的表:Java 使用多个默认值从缓存中提取时的代码气味?,java,caching,Java,Caching,我们有一个包含4列的表: A B C VALUE 1 2 0 100 0 3 3 200 0 0 7 400 0 0 0 700 该键由3列组成:A、B和C。 我们将此表保存在HashMap对象上 零表示默认值,因此如果找不到确切的键,则应根据以下逻辑拉取相关键: value = cache.get(new ImmutableTriple<>(a, b, c)); if (value != null) { return value; } value =
A B C VALUE
1 2 0 100
0 3 3 200
0 0 7 400
0 0 0 700
该键由3列组成:A、B和C。我们将此表保存在
HashMap
对象上
零表示默认值,因此如果找不到确切的键,则应根据以下逻辑拉取相关键:
value = cache.get(new ImmutableTriple<>(a, b, c));
if (value != null) {
return value;
}
value = cache.get(new ImmutableTriple<>(a, b, 0));
if (value != null) {
return value;
}
value = cache.get(new ImmutableTriple<>(a, 0, c));
if (value != null) {
return value;
}
value = cache.get(new ImmutableTriple<>(a, 0, 0));
if (value != null) {
return value;
}
value = cache.get(new ImmutableTriple<>(0, 0, 0));
if (value != null) {
return value;
}
value=cache.get(新的不可变三元组(a、b、c));
if(值!=null){
返回值;
}
value=cache.get(新的不可变三元组(a、b、0));
if(值!=null){
返回值;
}
value=cache.get(新的不可变三元组(a,0,c));
if(值!=null){
返回值;
}
value=cache.get(新的ImmutableTriple(a,0,0));
if(值!=null){
返回值;
}
value=cache.get(新的ImmutableTriple(0,0,0));
if(值!=null){
返回值;
}
问题是,通过使用默认值的3个ID的键获取会产生代码气味。有没有更好\更干净的方法可以做到这一点?您可以使用默认值为三元组的所有可能状态创建一个“掩码映射”,例如:
private static List<Integer[]> mask = new ArrayList<>();
static {
mask.add(new Integer[] {null, null, null});
mask.add(new Integer[] {0, null, null});
mask.add(new Integer[] {null, 0, null});
mask.add(new Integer[] {null, null, 0});
mask.add(new Integer[] {null, 0, 0});
mask.add(new Integer[] {0, null, 0});
mask.add(new Integer[] {0, 0, null});
mask.add(new Integer[] {0, 0, 0});
}
但我不确定这是否比你的“代码气味”更好)
编辑:
当然,如果避免创建中间集合(findFirst是一个简短的circut运算符),这将更加有效:
有时,如果分解循环使代码更具可读性,那么它并不一定是一件坏事 我建议您保持代码的原样,因为您马上就会看到,如果您试图压缩代码,很可能会导致更糟糕的结果。如果你坚持,继续阅读
我的想法很简单:您实际上是在尝试循环通过几个遮罩来用于匹配模式。本例中的掩码是“是使用id还是默认”
// true = use id (don't mask); false = use default (mask).
List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
matchMasks.add(new ImmutableTriple<>(true, true, true));
matchMasks.add(new ImmutableTriple<>(true, true, false));
matchMasks.add(new ImmutableTriple<>(true, false, true));
matchMasks.add(new ImmutableTriple<>(true, false, false));
matchMasks.add(new ImmutableTriple<>(false, false, false));
全部放在一个类中:
public class Test
{
private HashMap<ImmutableTriple<Integer, Integer, Integer>, Integer> cache = <your table here>;
private List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
public Test()
{
// true = use id (don't mask); false = use default (mask).
this.matchMasks.add(new ImmutableTriple<>(true, true, true));
this.matchMasks.add(new ImmutableTriple<>(true, true, false));
this.matchMasks.add(new ImmutableTriple<>(true, false, true));
this.matchMasks.add(new ImmutableTriple<>(true, false, false));
this.matchMasks.add(new ImmutableTriple<>(false, false, false));
}
private Integer match(int a, int b, int c)
{
Integer value = null;
// Loop through match rules.
for (ImmutableTriple<Boolean, Boolean, Boolean> mask : this.matchMasks)
{
// Check whether to apply mask.
int aId = mask.getLeft() ? a : 0;
int bId = mask.getMiddle() ? b : 0;
int cId = mask.getRight() ? c : 0;
// Try to match cache.
value = this.cache.get(new ImmutableTriple<>(aId, bId, cId));
// Stop if match found.
if (value != null) break;
}
return value;
}
}
公共类测试
{
私有HashMap缓存=;
私有列表匹配掩码=新的ArrayList();
公开考试()
{
//true=使用id(不屏蔽);false=使用默认值(屏蔽)。
this.matchMasks.add(新的ImmutableTriple(true,true,true));
this.matchMasks.add(新的ImmutableTriple(true,true,false));
this.matchMasks.add(新的ImmutableTriple(true、false、true));
this.matchMasks.add(新的ImmutableTriple(true、false、false));
this.matchMasks.add(新的ImmutableTriple(false,false,false));
}
私有整数匹配(整数a、整数b、整数c)
{
整数值=null;
//循环检查匹配规则。
for(不可变三重掩码:this.matchMasks)
{
//检查是否应用遮罩。
int-aId=mask.getLeft()?a:0;
int bId=mask.getMiddle()?b:0;
int-cId=mask.getRight()?c:0;
//尝试匹配缓存。
value=this.cache.get(新的不可变三元组(aId、bId、cId));
//如果找到匹配项,请停止。
如果(值!=null)中断;
}
返回值;
}
}
另外,对于这种特殊情况,由于0=默认值,您可以使用1和0代替掩码的true和false,并执行以下操作int-aId=mask.getLeft()*a代码>,但这并不重要
正如您所看到的,尽管我们将代码“压缩”到一个循环中,但其效果仍有争议。事实上,我认为这段代码实际上可读性较差。因此,有时坚持使用分解循环并不一定不好。为三重标识符创建一个自定义类并在equals
方法中包含匹配逻辑不是更好吗?@JoakimDanielson但如果相同的代码仍然存在,只需重写equals方法,这会使它更好吗?我的意思是,代码气味仍然存在,就在其他地方,对吗?你不必创建5个对象,只需创建一个,因为所有匹配逻辑都在equals
方法中,所以对我来说这将是一个改进
return triples.stream()
.map(triple -> cache.get(triple))
.findFirst()
.orElse(null);
Integer result = mask.stream()
.map(row -> genrateTriple(row, a, b, c))
.map(cache::get)
.findFirst()
.orElse(null);
// true = use id (don't mask); false = use default (mask).
List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
matchMasks.add(new ImmutableTriple<>(true, true, true));
matchMasks.add(new ImmutableTriple<>(true, true, false));
matchMasks.add(new ImmutableTriple<>(true, false, true));
matchMasks.add(new ImmutableTriple<>(true, false, false));
matchMasks.add(new ImmutableTriple<>(false, false, false));
private Integer match(int a, int b, int c)
{
Integer value = null;
// Loop through match rules.
for (ImmutableTriple<Boolean, Boolean, Boolean> mask : matchMasks)
{
// Check whether to apply mask.
int aId = mask.getLeft() ? a : 0;
int bId = mask.getMiddle() ? b : 0;
int cId = mask.getRight() ? c : 0;
// Try to match cache.
value = cache.get(new ImmutableTriple<>(aId, bId, cId));
// Stop if match found.
if (value != null) break;
}
return value;
}
public class Test
{
private HashMap<ImmutableTriple<Integer, Integer, Integer>, Integer> cache = <your table here>;
private List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
public Test()
{
// true = use id (don't mask); false = use default (mask).
this.matchMasks.add(new ImmutableTriple<>(true, true, true));
this.matchMasks.add(new ImmutableTriple<>(true, true, false));
this.matchMasks.add(new ImmutableTriple<>(true, false, true));
this.matchMasks.add(new ImmutableTriple<>(true, false, false));
this.matchMasks.add(new ImmutableTriple<>(false, false, false));
}
private Integer match(int a, int b, int c)
{
Integer value = null;
// Loop through match rules.
for (ImmutableTriple<Boolean, Boolean, Boolean> mask : this.matchMasks)
{
// Check whether to apply mask.
int aId = mask.getLeft() ? a : 0;
int bId = mask.getMiddle() ? b : 0;
int cId = mask.getRight() ? c : 0;
// Try to match cache.
value = this.cache.get(new ImmutableTriple<>(aId, bId, cId));
// Stop if match found.
if (value != null) break;
}
return value;
}
}