题
我有一个密封的特点,其实施由3个对象
sealed trait MyTrait {
...
}
object A extends MyTrait { ... }
object B extends MyTrait { ... }
object C extends MyTrait { ... }
我使用的Scalaz的验证机制,其中适用方法的目的A、B和C返回经过验证的类型。的对象,A、B和C不包含一些逻辑和我想要应用这种逻辑顺序,即,我想首先应用和检查什么样的结果是,在此基础上,决定如果我想打电话给B,或只是返回的经过验证的结果。我想重复这个直到我打C在这之后我只是回不管我获得作为结果的调C.
目前,我有一个静态的办法在那里我第一个电话,将结果传递到一个实用的方法和检查的结果,然后打电话给B。
def apply(request: Request): Validated[Result] = {
val vResultA = run(request, A)
val vResultB = if (isResultOk(vResultA)) run(request, B) else vResultA
if (isResultOk(vResultB)) run(request, C) else vResultB
}
有没有更好的方式做到这一点?任何建议或任何模式,我可以申请吗?
解决方案
我们将定义 成功的结果=的结果都确定, , 失败的结果=的结果,是不确定.
第一, A
, B
, , C
是所有物体的延伸 MyTrait
.因此,他们可以分为一系列或一个列表中的 MyTrait
.
val objects = Array(A, B, C) /* You can use List instead if you want. */
那类型的 objects
是 Array[MyTrait]
.
接下来,我们必须迭代,在这个阵列。
然而,只是打电话 map
在这个阵列的继续射即使以前的 isResultOk()
是 false
.
因此,我们将使用 Stream
而不是的 Array
.
让我们看看如何使用 Stream
可以停止调用 map
如果某些条件得到满足。
Array(1, 2, 3, 4, 5).map(i => {
println(i)
i + 100
}).takeWhile(_ <= 103).foreach(println(_))
输出的上述码将是:
1
2
3
4
5
101
102
103
所以, map()
结束,然后 takeWhile()
结束-- takeWhile()
并不影响叫 map()
.
然而,如果我们做同样的操作 Stream
,
Array(1, 2, 3, 4, 5).toStream.map(i => {
println(i)
i + 100
}).takeWhile(_ <= 103).foreach(println(_))
输出将是:
1
101
2
102
3
103
4
因此呼吁会 map() -> takeWhile() -> foreach() -> map() -> takeWhile() -> ...
在结束、4印刷和4+100=104>103将切 takeWhile()
.
以下要素将是不访问进一步。
因此,我们必须使用takeWhile?
objects.toStream.map(run(request, _)).takeWhile(isResultOk(_))
这将摆脱失败的结果,尽管我们需要第一个失败的结果,如果未发生。
(即这将使一个问题,如果有任何结果,是不确定。)
关于如何相反的功能 dropWhile()
?
objects.toStream.map(run(request, _)).dropWhile(isResultOk(_))
这将摆脱所有成功的结果,即使所有结果都取得了成功。
(即这将使一个问题,如果所有的结果都确定。)
因此,我们将使用 span()
.
c.span(p)
= (c.takeWhile(p), c.dropWhile(p))
我们将测试,如果有结果都是不确定。
如果有一个结果,是不确定,然后我们将返回的第一个这样的结果。
否则,我们将返回的最后结果,该结果确定。
val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
fail.headOption.getOrElse(succ.last)
fail.headOption
将返回 Some(fail's first element)
如果 fail
不是空的,否则 None
.
在摘要,
val objects = Array(A, B, C)
def apply(request: Request): Validated[Result] = {
val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
fail.headOption.getOrElse(succ.last)
}