Computation Expressions是面向方面编程的另一种方法吗?
这是F#解决跨领域问题的解决方案。
我查看了以下文章,并没有想到AOP(即面向方面编程)。
在article中,作者提供了一个处理日志记录的计算表达式的示例,但是在不模糊业务逻辑主要意图的情况下隔离了代码的实际日志记录方面。
我的想法准确吗?
答案 0 :(得分:9)
是的,monad是一种很好的(和惯用的)方法,可以解决跨领域的问题。 monad是一个更通用的概念,但可以使用的一个用途是在系统中建模效果。
在FP术语中,单词效果通常意味着副作用。诸如日志记录,审计,性能监控,缓存和计量等所有(根据定义)的跨领域问题都有副作用。因为他们涉及写作'数据到次要有状态资源,可以使用State或Writer monad建模。
其他跨界问题,如身份验证,授权和验证,通常可以通过Reader monad(或者可能是State monad)解决。
F#计算表达式提供了monadic组合器的语法糖(本质上是返回和 bind ),就像Haskell的do
符号一样。但是,与Haskell相反,除了已经内置到语言中的少数(async
,seq
)之外,您必须自己为monad定义计算表达式构建器。
使用monad来解决跨领域的问题与AOP不同。
在面向对象的编程中,对AOP有两种根本不同的看法:
正如我在my book中解释的那样,我认为编译时编织是解决问题的一种笨拙且不灵活的方式。使用Decorator是实现相同目标的更优雅和灵活的方式。
我对该陈述的动机是我偏好分离关注点。
如果你在OOP中使用编译时编织,你通常会有这样的代码(C#示例):
[Log]
public void SaveOrder(Order order)
{
// Implementation goes here...
}
这里的问题是,虽然问题是分开的,但它们仍然是耦合。除非您重新编译,否则您无法决定不从SaveOrder
登录。
使用计算表达式有点像:
log { return saveOrder order }
同样,横切关注点与实现一起编译。
然而,在相似性结束的地方,可以使用monadic组合器一起构成关注点,这在编译时编织中是不容易的。在OOP中,您无法轻松采用不日志记录的方法,并且可以“神奇地”'在将对象组合在一起时记录它。另一方面,使用monads,可以获取pure function并使用monadic上下文组合它。这种后期绑定的日志记录是structurally equivalent to using Decorators。
因此,我认为只要将此类代码推迟到应用程序的入口点(Composition Root),就可以将计算表达式用于横切关注点。