没有if-else的更具可读性的代码

几年前,我写一篇关于如何避免if-else语句序列的文章。 在那篇文章中,我演示了几种选择:

  • 正确的OOP设计的使用
  • 地图
  • 如果没有return ,请在case switch语句。

最近,我偶然发现了一个稍微复杂的用例。 这篇文章对此进行了描述,并详细介绍了Kotlin中可用的其他选项。

模拟一个简单的if ... else序列

让我们从建模简单的if-else语句序列开始。 想象一下,我们需要检查一个字母的值以返回与后者相关的整数。

如前一篇文章所述,if-else的一种简单替代方法是创建一个映射,以字母为键,以整数为值。

valmappings=mapOf(
  "A"to1,
  "B"to2,
  "C"to3,
  "D"to4,
  "E"to5,
  "F"to6,
  "G"to7
)

valresult=mappings["A"]
请记住,始终对键使用不可变类型!

使问题更加复杂

现在想象一下,代替检查一个值,需要检查两个不同的输入以计算返回值。 解决此问题的直接方法是使用嵌入式, if

if(input1=="A"){
  if(input2=="A")return1
  if(input2=="B")return2
  if(input2=="C")return3
  // and the rest
}elseif(input1=="B"){
  if(input2=="A")return2
  if(input2=="B")return4
  if(input2=="C")return6
  // and the rest
}
// and the rest

使用地图方法,这类似于:

valmappings=mapOf(
  "A"tomapOf(
    "A"to1,
    "B"to2,
    "C"to3
    // and the rest
  ),
  "B"tomapOf(
    "A"to2,
    "B"to4,
    "C"to6
    // and the rest
  )
  // and the rest
)

valresult=mappings["A"]["B"]

我相信以前的代码很难阅读:

  • 创建地图需要大量的嵌套代码
  • 获得结果是一个两步过程-首先获得一维地图,然后获得标量值
  • 键的顺序不应混淆: mappings["A"]["B"]与(可能)不同于mappings["B"]["A"]

解决复杂的问题

让我们停下来,然后将第一个序列建模为数组:

一个 C d Ë F G

1

 2

3

4

5

6

7

上述解决方案具有一维。 现在想象一下,选择是一个2D矩阵:

一个 C d Ë F G

A

1

 2

3

4

5

6

7

B

2

 4

6

8

10

12

14

C

3

 6

9

12

15

18

21

D

4

 8

12

16

20

24

28

E

5

 10

15

20

25

30

35

F

6

 12

18

24

30

36

42

G

7

 14

21

28

35

42

49

这类似于多重地图,即具有两个键的地图。 Java和Kotlin都不具有Multimap类型,但是库却具有:

  1. 例如, 番石榴里有一个
  2. 还有另一个在Apache Commons Lang中

由于使用了PairTriple类,因此使用Kotlin不需要多达3个尺寸的多图。

valmappings=mapOf(
  ("A"to"A")to1,
  ("A"to"B")to2,
  ("A"to"C")to3,
  ("B"to"A")to2,
  ("B"to"B")to4,
  ("B"to"C")to6
  // and the rest
)

valresult=mappings["A"to"B"]
对于尺寸大于3的键,请创建专用的不可变类型,并覆盖其equals()和hashCode()方法。

返回计算

在旧的帖子中,当代码没有返回结果而是调用了一个方法时,使用了一个switch

when(key){
  "A"to"A"->doSomething()
  "A"to"B"->doSomethingElse()
  "A"to"C"->andNowForSomethingCompletelyDifferent()
}

但是,将计算存储在地图中是更好的选择。 然后可以动态调用它:

valmappings=mapOf(
  ("A"to"A")to{doSomething()},
  ("A"to"B")to{doSomethingElse()}
  ("A"to"C")to{andNowForSomethingCompletelyDifferent()}
)

mappings["A"to"B"]?.invoke()

唯一的要求是所有计算都具有相同的签名:这里是一个不带输入参数的函数。

上面的代码中未使用返回值。 如果是这样,可以很容易地捕获它:

val result = mappings["A" to "B"]?.invoke()

如果在没有键匹配时需要默认值,则getOrDefault()函数是您的朋友:

valmappings=mapOf(
  ("A"to"A")to{doSomething()},
  ("A"to"B")to{doSomethingElse()}
  ("A"to"C")to{andNowForSomethingCompletelyDifferent()}
)

valresult=mappings.getOrDefault("A"to"E"){doDefault()}.invoke()

结论

在较早的文章中,我列出了一些简单的技术来避免与简单用例相关的if-else语句序列。 在本教程中,我展示了更先进的技术来满足更高级的用法:用于嵌套求值的多图,并在需要执行代码时将计算结果作为值存储在图中。

编写代码时,提高代码的可读性应该是第一要务。 它不需要花哨的技术,只需不断地努力就可以实现它。 认识和理解自己的语言以及可用的库对于实现该目标大有帮助。

翻译自: https://blog.frankel.ch/even-more-readable-code-without-if-else/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值