装饰者模式的function相当于?

什么是装饰devise模式的等价function编程?

例如,你将如何在function风格中编写这个特定的例子 ?

在函数式编程中,你会把一个给定的函数包装在一个新的函数中。

给你一个类似于你的问题引用的Clojure的例子:

我原来的绘图function:

(defn draw [& args] ; do some stuff ) 

我的函数包装:

 ; Add horizontal scrollbar (defn add-horizontal-scrollbar [draw-fn] (fn [& args] (draw-horizontal-scrollbar) (apply draw-fn args))) ; Add vertical scrollbar (defn add-vertical-scrollbar [draw-fn] (fn [& args] (draw-vertical-scrollbar) (apply draw-fn args))) ; Add both scrollbars (defn add-scrollbars [draw-fn] (add-vertical-scrollbar (add-horizontal-scrollbar draw-fn))) 

这些函数返回一个新的函数,可以在原始绘图函数的任何位置使用,也可以绘制滚动条。

curlfunction参数/组成是最接近的等价物。 然而,即使提出这个问题也是一个错误,因为存在弥补主语言弱点的模式。

如果C ++ / Java / C#/任何其他几乎相同的语言具有内置的语言装饰function,你不会认为它是一种模式。 恰恰恰巧,“模式”是早期绑定的命令式目标语言(通常不使用自动装箱)和相对较薄的根类协议来构造系统的模式。

编辑:也有很多这些研究作为模式在这些语言,因为没有明显的内置高阶函数,更高阶的打字,而types系统是相对无用的。 显然,这些语言并不是一个普遍的问题,但是当这些模式开始被编纂时,这些问题就出现了。

您可以通过将函数包装到其他函数中来“装饰”函数,通常使用某种forms的高阶函数来执行包装。

Clojure简单的例子:

 ; define a collection with some missing (nil) values (def nums [1 2 3 4 nil 6 7 nil 9]) ; helper higher order function to "wrap" an existing function with an alternative implementation to be used when a certain predicate matches the value (defn wrap-alternate-handler [pred alternate-f f] (fn [x] (if (pred x) (alternate-f x) (fx)))) ; create a "decorated" increment function that handles nils differently (def wrapped-inc (wrap-alternate-handler nil? (constantly "Nil found!") inc)) (map wrapped-inc nums) => (2 3 4 5 "Nil found!" 7 8 "Nil found!" 10) 

这种技术在function库中被广泛使用。 一个很好的例子是使用Ring中间件来封装Web请求处理程序 – 链接的示例将围绕任何现有处理程序的html请求进行参数处理。

像这样的东西:

 class Window w where draw :: w -> IO () description :: w -> String data VerticalScrollingWindow w = VerticalScrollingWindow w instance Window w => Window (VerticalScrollingWindow w) where draw (VerticalScrollingWindow w) = draw w >> drawVerticalScrollBar w -- `drawVerticalScrollBar` defined elsewhere description (VerticalScrollingWindow w) = description w ++ ", including vertical scrollbars" 

在Haskell中,这个OO模式几乎可以直接翻译,你只需要一个字典。 请注意,直接翻译并不是一个好主意。 试图迫使一个面向对象的概念进入Haskell是一种背道而语,但是你问它是这样的。

窗口界面

Haskell有类,它具有一个接口的所有function,然后是一些。 所以我们将使用下面的Haskell类:

 class Window w where draw :: w -> IO () description :: w -> String 

抽象WindowDecorator类

这一点是比较棘手的,因为Haskell没有inheritance的概念。 通常我们根本不会提供这个types,让装饰器直接实现Window ,但是让我们完全按照例子来做。 在这个例子中, WindowDecorator是一个窗口,带有一个窗口的构造函数,让我们用一个给装饰窗口的函数来增加窗口。

 class WindowDecorator w where decorate :: (Window a) => a -> wa unDecorate :: (Window a) => wa -> a drawDecorated :: wa -> IO () drawDecorated = draw . unDecorate decoratedDescription :: wa -> String decoratedDescription = description . unDecorate instance (WindowDecorator w) => Window w where draw = drawDecorated description = decoratedDescription 

请注意,我们提供了Window的默认实现,它可以被replace,并且WindowDecorator所有实例WindowDecorator将是一个Window

装饰者

然后做装饰可以做如下:

 data VerticalScrollWindow w = VerticalScrollWindow w instance WindowDecorator VerticalScrollWindow where decorate = VerticalScrollWindow unDecorate (VerticalScrollWindow w ) = w drawDecorated (VerticalScrollWindow w ) = verticalScrollDraw >> draw w data HorizontalScrollWindow w = HorizontalScrollWindow w instance WindowDecorator HorizontalScrollWindow where decorate = HorizontalScrollWindow unDecorate (HorizontalScrollWindow w .. ) = w drawDecorated (HorizontalScrollWindow w ..) = horizontalScrollDraw >> draw w 

整理起来

最后我们可以定义一些窗口:

 data SimpleWindow = SimpleWindow ... instance Window SimpleWindow where draw = simpleDraw description = simpleDescription makeSimpleWindow :: SimpleWindow makeSimpleWindow = ... makeSimpleVertical = VerticalScrollWindow . makeSimpleWindow makeSimpleHorizontal = HorizontalScrollWindow . makeSimpleWindow makeSimpleBoth = VerticalScrollWindow . HorizontalScrollWindow . makeSimpleWindow 

好吧,首先我们试着找出关于OOP的所有装饰器模式的主要组件。 这个模式基本上用来装饰,即添加额外的function到现有的对象 。 这是这种模式最简单的定义。 现在,如果我们试图在FP的世界里find这个定义中存在的相同的组件,我们可以说在FP中没有新的function和对象,而FP则有你所谓的各种数据或数据结构表格 。 所以在FP中,这种模式变成了,为FP数据结构增加了额外的function,或者增加了一些附加function的现有function。

Clojure的喜悦在第13.3章“缺乏devise模式”中讨论了这个问题。 根据JoC, ->->>macros有点类似于装饰器模式。

我不是100%肯定的,但我认为C9高级函数式编程系列讲座解释了这个问题真的很好。

除此之外,您可以在F#中使用相同的技术(它只支持相同的OO机制),在这种特殊情况下,我会这样做。

我想这是一个问题,你试图解决的问题。

下面是一个使用JavaScript的Web服务器API JSGI的例子:

 function Log(app) { return function(request) { var response = app(request); console.log(request.headers.host, request.path, response.status); return response; }; } var app = Logger(function(request) { return { status: 200, headers: { "Content-Type": "text/plain" }, body: ["hello world"] }; } 

当然,兼容的中间件可以堆叠(例如, Lint(Logger(ContentLength(app)))