我有一个密封的特性,由3个物体实现
sealed trait MyTrait {
...
}
object A extends MyTrait { ... }
object B extends MyTrait { ... }
object C extends MyTrait { ... }
我使用Scalaz的验证机制,其中对象A,B和C的apply方法返回验证类型。对象A,B和C确实包含一些逻辑,我想顺序应用这个逻辑,即,我想首先应用A并检查A的结果是什么,并根据它,决定我是否要调用B或只是返回验证结果。我想重复这个,直到我点击C,之后我只返回因调用C而获得的任何内容。
目前我有一个静态方法,我首先调用A,将A的结果传递给实用程序方法并检查结果,然后调用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
}
有更好的方法吗?我可以申请的任何建议或模式吗?
答案 0 :(得分:3)
我们将定义成功结果=结果正常,失败结果=结果不正常。
首先,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>将在takeWhile()
中删除103
以下元素将不会被进一步访问。
那么,我们必须使用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)
}