我的任务是将审计跟踪附加到一堆计算之后用于重构值(即具有业务领域知识的人来解读出错的地方。)当前代码看起来像这样:
def doSomething = f(x) orElse g(x,y,z) orElse h(p,q,r) orElse default
其中每个都返回一个选项。新代码应返回(Option,Audit。)元组
我已将其实现为
def doSomething = f(x) match{
case None => g_prime(x,y,z)
case x @ Some(_) => (x, SomeAuditObject)
}
//and taking some liberties with the actual signature...
def g_prime(x,y,z) = g(x,y,z) match{
依此类推,直至“默认”。每个函数链接到下一个和下一个,依此类推。我不喜欢它。感觉太必要了。我错过了什么。有一些思考这个问题的方法,我只是没有看到。除了将返回值包装到另一个选项中之外,它是什么?
答案 0 :(得分:8)
您可以使用Monads撰写留下审计跟踪的转换。您可以在Monad内部进行审核。有关详细信息,请查看this answer。
我试着为你制作一个例子。我不知道如何处理for-comprehension的最后一步,即map
,并且不提供审计跟踪。如果您不允许使用map
,则不能使用for-comprehensions,但必须使用flatMap
的普通电话。
case class WithAudit[A](value: A, audit: String){
def flatMap[B](f: A => WithAudit[B]): WithAudit[B] = {
val bWithAudit = f(value)
WithAudit(bWithAudit.value, audit + ":" + bWithAudit.audit)
}
def map[B](f: A => B): WithAudit[B] = {
WithAudit(f(value), audit + ":applied unknown function")
}
}
def doSomething(in: Option[Int]): WithAudit[Option[Int]] = WithAudit(
in.map(x => x - 23),
"substract 23"
)
def somethingElse(in: Int): WithAudit[String] = WithAudit(
in.toString,
"convert to String"
)
val processed = for(
v <- WithAudit(Some(42), "input Some(42)");
proc <- doSomething(v);
intVal <- WithAudit(proc.getOrElse(0), "if invalid, insert default 0");
asString <- somethingElse(intVal)
) yield asString
println(processed)
输出
WithAudit(
19,
input Some(42)
:substract 23
:if invalid, insert default 0
:convert to String
:applied unknown function
)
使用flatMap
处理该值会强制执行审核。如果您没有提供map
并限制如何从monad中提取值(如果这样做,可能会写一个日志输出),您可以非常安全地假设将记录值的每个转换。获得该值后,您将在日志中获得一个条目。
答案 1 :(得分:2)
您是否只审核f
,g
等的成功执行?
如果是这样,我会让doSomething返回Option[(YourData, Audit)]
(而不是(Option[YourData], Audit)
)。然后你可以组成这样的函数:
def doSomething = (f(x) andThen (t => (t, audit_f(x)))) orElse
(g(x, y, z) andThen (t => (t, audit_g(x, y, z)))) orElse
... etc.