Functional equivalent of decorator pattern?

后端 未结 10 2236
悲&欢浪女
悲&欢浪女 2021-02-02 06:34

What is the functional programming equivalent of the decorator design pattern?

For example, how would you write this particular example in a functional style?

10条回答
  •  孤城傲影
    2021-02-02 07:14

    In Haskell, this OO pattern translates pretty much directly, you only need a dictionary. Note that a direct translation is not actually a good idea. Trying to force a OO concept into Haskell is kind of backwords, but you asked for it so here it is.

    The Window Interface

    Haskell has classes, which has all the functionality of an Interface and then some. So we will use the following Haskell class:

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

    The Abstract WindowDecorator class

    This one is a bit more tricky since Haskell has no concept of inheritance. Usually we would not provide this type at all and let the decorators implement Window directly, but lets follow the example completely. In this example, a WindowDecorator is a window with a constructor taking a window, lets augment this with a function giving the decorated window.

    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
    

    Note that we provide a default implementation of Window, it can be replaced, and all instances of WindowDecorator will be a Window.

    The decorators

    Making decorators can then be done as follows:

    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
    

    Finishing Up

    Finally we can define some windows:

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

提交回复
热议问题