Functional programming 函数式编程的实体

Functional programming 函数式编程的实体,functional-programming,solid-principles,Functional Programming,Solid Principles,我来自OOP语言,熟悉面向对象设计的坚实原则。似乎其中的一些将适合函数式编程模型,而其他部分在缺少状态的世界中毫无意义。重构功能代码有类似的原则吗?据我所知(我不是专家),坚实的原则不能告诉任何关于状态的事情。它们也应该适用于函数式编程语言。它们更多的是关于如何实现模块化的建议 其中一些是相当明显的,或者至少是众所周知的。单一责任是UNIX原则“只做一件事,把它做好”,这在函数式语言中更为流行,在函数式语言中,“组合”也被广泛使用。接口分离原则也是很自然的(让您的接口模块化并保持正交概念分离)。

我来自OOP语言,熟悉面向对象设计的坚实原则。似乎其中的一些将适合函数式编程模型,而其他部分在缺少状态的世界中毫无意义。重构功能代码有类似的原则吗?

据我所知(我不是专家),坚实的原则不能告诉任何关于状态的事情。它们也应该适用于函数式编程语言。它们更多的是关于如何实现模块化的建议

其中一些是相当明显的,或者至少是众所周知的。单一责任是UNIX原则“只做一件事,把它做好”,这在函数式语言中更为流行,在函数式语言中,“组合”也被广泛使用。接口分离原则也是很自然的(让您的接口模块化并保持正交概念分离)。最后,依赖倒置只是“抽象”的一个名称,在函数式编程中无处不在

“OL”原则,开放/封闭和LSP,更倾向于基于继承作为核心软件工程概念的语言。默认情况下,函数语言值/模块没有开放递归,因此“实现继承”仅在非常特定的情况下使用。最好是合成物。我不确定在那种情况下你应该如何解释开/关原则。您可以考虑它是封装的,功能程序也使用很多,使用抽象类型等。

最后,Liskov替代原则似乎与继承有关。函数式语言并不总是使用子类型,但当它们使用子类型时,确实假定“派生类型”应该保留“基类型”的规范。函数式程序员当然会小心地指定并尊重其程序、模块等的接口和属性,并且在编程、重构等过程中,可能会基于这些规范使用代数推理(这与此等效,因此我可以替换…)。然而,一旦你摆脱了“默认继承”的想法,接口冲突的问题要少得多,因此LSP不像在OOP中那样被强调为重要的保护措施。

介绍了坚实的原则,以及如何在Clojure中应用这些原则

它展示了这些原则在函数世界和OOP中的作用,因为我们仍然需要解决相同的底层问题。总的来说,它让我觉得函数式编程更适合于实体设计。

“伦敦JCP委员会成员Richard Warburton在其报告中描述了SOLID原则,作为Robert C.Martin在21世纪初确定的成熟面向对象编程设计原则的一个例子,并研究了五个原则中的每一个,试图找到功能上的等价物或至少是功能方面的相关内容。 Richards的经验是,尽管许多开发人员不知道如何在功能设计中使用他们现有的设计技能,但功能编程通常有助于实现坚实的原则,而且功能思维实际上有助于实现面向对象的一个重要方面,即封装。”

进一步资料:

  • 面向对象设计原则和功能编程-

  • 函数式编程的固体原理等价物-


实际上,SOLID对于函数式编程有一个更好的原则可能是个好主意:

  • SRP
    只做一件事
    最初是从命令式编程中提取出来的。拥有小而集中的函数是好的

  • OCP:允许您在不修改代码的情况下更改行为是很好的。函数式编程使用的是高阶函数,而不是继承,但这一原则仍然适用

  • LSP:在函数式编程中遵守某些接口约定与在面向对象编程中一样好。如果排序函数使用比较器,则您会期望“0等于、小于等于提供负面结果、大于正面结果”的行为

  • ISP:大多数函数式语言仍然具有结构。指定函数所需的最小数据集仍然是一种好的做法。要求数据具有最不特定的接口(当枚举不能正常工作时,为什么要使用INT列表?)仍然是一种好的做法

  • DIP:在函数编程中,为函数指定参数(或使用高阶函数检索参数)而不是对函数进行硬编码以获取某些值与在面向对象编程中一样好


即使在进行面向对象编程时,这些原则中的许多也适用于对象中方法的设计。

事实上,走到极致的SOLID本质上是面向对象语言中具有不变状态的函数式编程。此注释不仅有助于查看OO和FP之间的联系,而且有助于理解更直观的是,坚实的原则。谢谢。OCP不一定要继承,这是一个常见的误解,可能是因为它经常被解释为策略模式或模板方法模式。但是有黑匣子模块,也可以重用和扩展,而无需改变它们的内部结构,只是通过传递它们的(可能是函数)参数与继承毫无关系,甚至“策略模式”也更容易使用函子而不是策略对象层次结构来实现。