Ste*_*itz 40 f# haskell design-patterns functional-programming clojure
什么是函数式编程相当于装饰器设计模式?
例如,您如何在功能样式中编写此特定示例?
Chr*_*erg 33
在函数式编程中,您可以将给定函数包装在新函数中.
给出一个类似于你问题中引用的Clojure设计示例:
我原来的绘图功能:
(defn draw [& args]
; do some stuff
)
Run Code Online (Sandbox Code Playgroud)
我的函数包装器:
; 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)))
Run Code Online (Sandbox Code Playgroud)
这些返回一个新函数,可以在使用原始绘图函数的任何地方使用,但也可以绘制滚动条.
Mar*_*cin 16
卷曲功能参数/组成是最接近的等价物.然而,即使提出这个问题也是错误的,因为模式的存在是为了弥补宿主语言中的弱点.
如果C++/Java/C#/任何其他几乎完全相同的语言都具有内置于该语言中的装饰功能,则不会将其视为模式.它只是恰巧,"模式"是在早期绑定必须面向目标的语言的结构体系的模式,通常没有自动装箱,并与相对较薄的协议根类.
编辑:还有很多这些被研究作为这些语言中的模式,因为没有明显内置的高阶函数,更高阶的类型,并且类型系统相对无用.显然,这不是这些语言的普遍问题,但在这些模式开始编纂时,这些问题就出现了.
mik*_*era 11
您可以通过将函数包装在其他函数中来"装饰"函数,通常使用某种形式的高阶函数来执行换行.
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)
(f x))))
; 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)
Run Code Online (Sandbox Code Playgroud)
该技术广泛用于功能库中.一个很好的例子是使用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"
Run Code Online (Sandbox Code Playgroud)
在Haskell中,这个OO模式几乎直接翻译,你只需要一本字典.请注意,直接翻译实际上并不是一个好主意.试图强迫一个OO概念进入Haskell是一种背叛词,但是你在这里问这个问题.
窗口界面
Haskell有类,它具有接口的所有功能,然后是一些.所以我们将使用以下Haskell类:
class Window w where
draw :: w -> IO ()
description :: w -> String
Run Code Online (Sandbox Code Playgroud)
Abstract WindowDecorator类
这个有点棘手,因为Haskell没有继承的概念.通常我们根本不提供这种类型,让装饰器Window
直接实现,但让我们完全按照例子.在这个例子中,a WindowDecorator
是一个带有构造函数窗口的窗口,让我们用一个给出装饰窗口的函数来扩充它.
class WindowDecorator w where
decorate :: (Window a) => a -> w a
unDecorate :: (Window a) => w a -> a
drawDecorated :: w a -> IO ()
drawDecorated = draw . unDecorate
decoratedDescription :: w a -> String
decoratedDescription = description . unDecorate
instance (WindowDecorator w) => Window w where
draw = drawDecorated
description = decoratedDescription
Run Code Online (Sandbox Code Playgroud)
请注意,我们提供了一个默认实现Window
,它可以被替换,并且所有实例都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
Run Code Online (Sandbox Code Playgroud)
整理起来
最后我们可以定义一些窗口:
data SimpleWindow = SimpleWindow ...
instance Window SimpleWindow where
draw = simpleDraw
description = simpleDescription
makeSimpleWindow :: SimpleWindow
makeSimpleWindow = ...
makeSimpleVertical = VerticalScrollWindow . makeSimpleWindow
makeSimpleHorizontal = HorizontalScrollWindow . makeSimpleWindow
makeSimpleBoth = VerticalScrollWindow . HorizontalScrollWindow . makeSimpleWindow
Run Code Online (Sandbox Code Playgroud)