假设我们有一个Order类和一个方法,其中一些服务执行一系列操作
fun doStuff(order: Order): Order {
val orderByServiceA = serviceA.operationA(order: Order)
val orderByServiceB = serviceB.operationB(orderByServiceA: Order)
val orderByServiceC = serviceC.operationC(orderByServiceB: Order)
return orderByServiceC
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个可以由服务实现的通用接口
interface IOrderService {
fun operation(order: Order): Order
}
Run Code Online (Sandbox Code Playgroud)
于是上面的方法就变成了
fun doStuff(order: Order): Order {
val orderByServiceA = serviceA.operation(order: Order)
val orderByServiceB = serviceB.operation(orderByServiceA: Order)
val orderByServiceC = serviceC.operation(orderByServiceB: Order)
return orderByServiceC
}
Run Code Online (Sandbox Code Playgroud)
此代码中有某种重复,因此下一步是使此函数对扩展开放并对修改关闭。我将IOrderService的所有实例添加到列表中,因此函数会发生如下变化
fun doStuff(order: Order): Order {
orderServices.forEach { service ->
service.operation(order)
}
...
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案非常好,因为如果我想添加另一个实现操作功能的服务,这是很容易做到的。
但是有一个问题..最后一个解决方案中传递的订单对象对于所有服务都是相同的,因此建议的解决方案与第一个实现不同。每个服务都需要根据之前的结果执行操作功能
所以我在这一点上陷入了困境,因为我想找到一个干净的解决方案..我正在考虑一些设计模式,例如观察者(但它是一个一对多的解决方案,但事实并非如此)纪念品模式(但我可能会继续有一个连续的操作列表),发布订阅......但我认为这些都不是正确的选择。它就像多米诺骨牌,其中对象传递给第一个服务,结果传递给第二个服务,等等,当然还有 doStuff 方法返回的最终结果。
有什么建议来完成最后一段代码吗?多谢!
我认为你真的把所有这些模式搞得太复杂了。你所描述的是......只是一个简单的循环!
fun doStuff(order: Order): Order {
var curr = order
for (service in orderServices) {
curr = service.operation(curr)
}
return curr
}
Run Code Online (Sandbox Code Playgroud)
如果您喜欢函数式编程,那么可以通过减少/折叠服务列表来更简单地解决它:
fun doStuff(order: Order): Order {
return orderServices.fold(order) { o, svc -> svc.operation(o) }
}
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅文档fold():https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce
@broot\'s 答案涵盖了执行此操作的一般方法\xe2\x80\x94就像他们所说的那样,是在迭代某些内容时累积fold结果的基本操作\xe2\x80\x94但是如果你想明确地写出来,你可以链接你的电话:
fun doStuff(order: Order) = \n order.let { serviceA.operationA(it) }\n .let { serviceB.operationB(it) }\n .let { serviceC.operationC(it) }\nRun Code Online (Sandbox Code Playgroud)\n如果您使用函数引用,其中参数或接收器自动传递给您正在引用的函数,您可以这样做:
\nfun doStuff(order: Order) = \n order.let(serviceA::operationA)\n .let(serviceB::operationB)\n .let(serviceC::operationC)\nRun Code Online (Sandbox Code Playgroud)\n因此,您最终会得到这个非常清晰的操作管道,原始操作Order正在逐步传递。
另一个好处是你的类型不需要保持一致:operationB可以从 中获取完全不同的参数operationA,重要的是出来的类型operationA与进入 的类型相同operationB。而使用折叠时,累加器\xe2\x80\x94(从一个步骤传递到下一步的值 \xe2\x80\x94)是一种固定类型,并且您正在迭代的函数集合也具有固定类型;在这种情况下,他们都需要获取Order并返回Order。它们都很有用,并且您可以选择\xe2\x80\x94,使用适合情况的任何内容!
| 归档时间: |
|
| 查看次数: |
40 次 |
| 最近记录: |