Ale*_*xey 15 oop functional-programming clojure reusability
Clojure语言的创建者声称 "开放的,大型的函数集在一个开放的,小的,可扩展的抽象集合上运行是算法重用和库互操作性的关键".显然,它与典型的OOP方法相矛盾,在这种方法中,您创建了大量的抽象(类)和一组相对较少的函数.请建议一本书,一本书中的章节,一篇文章或您的个人经历,详细说明这些主题:
*MFUFA:"很少抽象的功能"
And*_*erg 18
编程中有两个主要的"抽象"概念:
[编辑:这两个是双重的.第一个是客户端抽象,第二个实现者抽象(如果你关心这些事情:在形式逻辑或类型理论方面,它们分别对应于普遍和存在量化).
在OO中,该类是用于实现两种抽象的厨房接收器功能.
Ad(1),几乎每个"模式"都需要定义一个自定义类(或几个).另一方面,在函数式编程中,您通常需要更轻量级和直接的方法来实现相同的目标,特别是函数和元组.经常指出,例如,来自GoF的大多数"设计模式"在FP中是多余的.
Ad(2),如果您没有可变状态在您需要检查的所有地方挥之不去,则需要稍微减少封装.您仍然在FP中构建ADT,但它们往往更简单,更通用,因此您需要更少的ADT.
当您以面向对象的方式编写程序时,您将重点放在根据数据类型表达域区域.乍一看,这看起来是个好主意 - 如果我们与用户合作,为什么不上课User呢?如果用户出售和购买汽车,为什么不上课Car呢?通过这种方式,我们可以轻松维护数据和控制流程 - 它只反映现实世界中事件的顺序.虽然这对于域对象来说非常方便,但对于许多内部对象(即不反映现实世界中的任何内容但仅出现在程序逻辑中的对象),它并不是那么好.也许最好的例子是Java中的许多集合类型.在Java(以及许多其他OOP语言)中,有两个数组List.在JDBC中,ResultSet它也是一种集合,但不实现Collection接口.对于输入,您经常会使用InputStream它提供接口来顺序访问数据 - 就像链表一样!但是它也没有实现任何类型的集合接口.因此,如果您的代码使用数据库并使用ResultSet它将更难为文本文件重构它InputStream.
MFUFA原则教会我们不要太注意类型定义,更多注意常见的抽象.出于这个原因,Clojure为所有提到的类型引入了单一抽象 - 序列.任何迭代都会自动强制转换为序列,流只是惰性列表,结果集可以很容易地转换为以前的类型之一.
另一个例子是使用PersistentMap结构和记录的接口.使用这样的通用接口,可以很容易地创建可重用的子例程,并且不需要花费大量时间来进行重构.
总结并回答您的问题:
UserList- List<User>在大多数情况下足够好.UserList(例如,当它应该具有许多附加功能时),请将两者List和Iterable接口添加到其定义中.final或者是所有字段private,所以派生类不能访问它们(例如,向第一类添加新函数String应该实现额外的类StringUtils).尽管如此,我上面描述的规则使得在OOP代码中使用MFUFA变得更加容易.最好的例子是Clojure本身,它以OO风格优雅地实现,但仍然遵循MFUFA原则.UPD.我记得面向对象和功能样式之间差异的另一种描述,可能总结得更好我上面所说的:OO风格的设计程序是根据数据类型(名词)来思考,而功能风格的设计则是根据操作来思考(动词).你可能会忘记一些名词是相似的(例如忘记继承),但是你应该永远记住在实践中许多动词做同样的事情(例如有相同或类似的接口).
我认为您没有意识到图书馆和程序之间存在差异。
运行良好的 OO 库通常会生成少量抽象,程序使用这些抽象为其领域构建抽象。较大的面向对象库(和程序)使用继承来创建不同版本的方法并引入新方法。
所以,是的,同样的原则也适用于 OO 库。
| 归档时间: |
|
| 查看次数: |
1073 次 |
| 最近记录: |