在 Haskell 中做例子的技巧是使用函数而不是类:
-- FooBar is like a base class
-- with methods foo and bar.
-- I've interpreted your example liberally
-- for purposes of illustration.
-- In particular, FooBar has two methods -
-- foo and bar - with different signatures.
data FooBar = FooBar {
foo :: IO (),
bar :: Int -> Int
}
-- Use functions for classes, like in Javascript.
-- This doesn't mean Haskell is untyped, it just means classes are not types.
-- Classes are really functions that make objects.
fooClass :: Int -> FooBar
fooClass n = FooBar {
foo = putStrLn ("Foo " ++ show n)
bar = \n -> n+1
}
barClass :: FooBar
barClass = FooBar {
foo = putStrLn "Bar ",
bar = \n -> n * 2
}
-- Now we can define a function that uses FooBar and it doesn't matter
-- if the FooBar we pass in came from fooClass, barClass or something else,
-- bazClass, say.
foobar (FooBar foo bar) = do
-- invoke foo
foo
-- use bar
print (bar 7)
这里FooBar
是“开放扩展”,因为我们可以FooBar
用不同的行为创造尽可能多的价值。
FooBar
要使用另一个字段“扩展” baz
,而不更改FooBar
,fooClass
或者barClass
,我们需要声明一个FooBarBaz
包含 的类型FooBar
。我们仍然可以使用我们的foobar
函数,我们只需要先从第一个中FooBar
提取FooBarBaz
。
到目前为止,我一直在接近 OOP。这是因为 Bertrand Meyer 将开放封闭原则表述为需要 OOP 或类似的东西:
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭
特别是,“扩展”一词传统上被解释为“子类化”。如果您准备将原理解释为仅仅是“具有扩展点”,那么任何以另一个函数作为参数的函数都是“开放扩展”。这在函数式编程中很常见,以至于它不被视为原则。“参数化原则”听起来不一样。