【问题标题】:How to model inheritance relationship in Functional Programming如何在函数式编程中建模继承关系
【发布时间】:2019-01-07 06:13:10
【问题描述】:

面向对象的编程范式使用继承来建模遵循泛化-专业化关系的实体之间的关系。在这里,基类用于封装一组实体的公共(通用)属性和行为,派生类通过添加附加属性和/或添加/修改现有行为来扩展基类。

作为函数式编程的新手,我需要有关在 F# 等函数式语言中建模此类关系的指导。

例如模拟如下简单情况的最佳方法是什么:

abstract class Tutorial { 
  private String topic;
  abstract public void learn();
}

class VideoTutorial extends Tutorial {
  private float duration;
  public void learn () {
    System.out.println ("Watch Video");
  }
}

class PDFTutorial extends Tutorial {
  private int pageCount;
  public void learn () {
    System.out.println ("Read PDF");
  }
}

然后稍后使用 Tutorials 集合并调用 learn 来观察多态行为。

【问题讨论】:

    标签: oop inheritance f# functional-programming


    【解决方案1】:

    在功能设计中,您对事物的看法略有不同,因此这些想法​​不会完美映射。通常,功能设计更侧重于表达您正在使用的实体的数据类型。在您的情况下,您可以使用有区别的联合定义 TutorialKind 是视频或 PDF,然后 Tutorial 将是包含一种类型及其主题的记录:

    type TutorialKind = 
      | VideoTutorial of duration:float
      | PDFTutorial of pageCount:int
    
    type Tutorial = 
      { Kind : TutorialKind
        Topic : string }
    

    请注意,这仅保留有关教程的数据。任何功能都可以在与教程类型匹配的函数中实现:

    let learn tutorial = 
      match tutorial.Kind with
      | VideoTutorial _ -> printfn "Watch video"
      | PDFTutorial _ -> printfn "Read PDF"
    

    请注意,它可以在与 OO 版本不同的方向上进行扩展。在 OO 中,您可以轻松地添加新的子类;在这里您可以轻松添加新功能。在实践中,函数式人员通常对这种变化感到满意,但 F# 是一种混合语言,如果您需要“OO 风格的可扩展性”,您可以轻松使用接口。

    【讨论】:

    • 谢谢,现在我明白了思维过程的变化。但是用这种方法,是不是意味着万一我以后想添加AudioTutorial,我需要修改这两种类型以及学习功能。请指导我,OO 方法是否更适合这种情况。
    • @S.Singh - 是的,这意味着如果要添加AudioTutorial,则需要修改TutorialKind 类型和learn 函数。但是,如果您想添加一个函数来执行教程中的其他操作,您只需要编写一个函数(而不是修改所有类,您必须在 OO 中这样做)。所以,视角的改变是双向的……在 F# 中,函数式风格是一个很好的默认值,但是如果你正在使用插件构建一些你真正需要 OO 类型的可扩展性的东西,你可以使用 OO 和接口。
    • 是的,要添加新类型的教程,您确实需要修改类型和所有使用它的函数。另一方面,在 C# 中,要添加新的操作,您确实需要修改每个现有类型。通常认为编程语言很难同时拥有这两种方式。这个问题很常见,它有自己的名字——Expression Problem。 C# 只解决了一半的问题,而 F# 解决了这两个问题,但不能同时解决。
    • @FyodorSoikin - 您能否解释一下“F# 解决了这两个问题,但不能同时解决”。它是指语言的混合性质,我们可以在其中以函数方式或面向对象方式对数据进行建模......
    • 是的。在 F# 中,您可以使用类和接口对域进行建模,也可以使用可区分联合进行建模。前者为您提供了添加新类型的简便方法,后者为您提供了添加新操作的简便方法。但你不能同时做这两件事。
    猜你喜欢
    • 2020-05-30
    • 2010-12-06
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 2021-07-30
    相关资源
    最近更新 更多