功能相当于装饰模式?

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#/任何其他几乎完全相同的语言都具有内置于该语言中的装饰功能,则不会将其视为模式.它只是恰巧,"模式"是在早期绑定必须面向目标的语言的结构体系的模式,通常没有自动装箱,并与相对较薄的协议根类.

编辑:还有很多这些被研究作为这些语言中的模式,因为没有明显内置的高阶函数,更高阶的类型,并且类型系统相对无用.显然,这不是这些语言的普遍问题,但在这些模式开始编纂时,这些问题就出现了.

  • 是的,他们是成语,因为没有直接的语言支持,语言使得做好这些事情变得非常重要.因此,成语如何做得好. (7认同)
  • @Marcin:在Clojure的实用工作室Rich Hickey说'模式意味着"我的语言已经用完了."',这是这个讨论的合适引用:-) (5认同)
  • 确实是@Marcin,但在以"do"表示形式引入语言支持之前,这几乎是一种模式(在某些情况下我仍然称之为功能模式).然而,Haskell有一些优点,使它看起来不像一个模式(运算符支持,类型类和简洁的lambda表示法). (2认同)

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请求的参数处理.


dav*_*420 6

像这样的东西:

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)

  • 为什么是类型类,而不是简单地使用`data Window = Window {draw :: IO(),description :: String}`? (3认同)
  • 这是haskell代码,还是?也许说某个地方,对于初学者? (2认同)

Has*_*ant 6

在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)