函数式编程和依赖倒置:如何抽象存储?

2023-12-23

我正在尝试创建一个具有较低级别库的解决方案,该库将知道在调用某些命令时需要保存和加载数据,但保存和加载函数的实现将在特定于平台的项目中提供它引用较低层的库。

我有一些模型,例如:

type User = { UserID: UserID
              Situations: SituationID list }

type Situation = { SituationID: SituationID }

我想做的是能够定义和调用函数,例如:

do saveUser ()
let user = loadUser (UserID 57)

有没有什么方法可以在函数式习惯用法中清楚地定义它,最好同时避免可变状态(无论如何这都不是必需的)?

一种方法可能如下所示:

type IStorage = {
    saveUser: User->unit;
    loadUser: UserID->User }

module Storage =
    // initialize save/load functions to "not yet implemented"
    let mutable storage = {
        saveUser = failwith "nyi";
        loadUser = failwith "nyi" }

// ....elsewhere:
do Storage.storage = { a real implementation of IStorage }
do Storage.storage.saveUser ()
let user = Storage.storage.loadUser (UserID 57)

这有多种变化,但我能想到的所有变化都涉及某种未初始化的状态。 (在 Xamarin 中,还有 DependencyService,但这本身就是我想避免的依赖项。)

有没有什么方法可以编写调用尚未实现的存储函数的代码,然后实现它,而不使用可变状态?

(注意:这个问题与存储本身无关——这只是我正在使用的示例。它是关于如何在不使用不必要的可变状态的情况下注入函数。)


这里的其他答案也许会教您如何在 F# 中实现 IO monad,这当然是一个选择。不过,在 F# 中,我经常只是将函数与其他函数组合。您不必定义“接口”或任何特定类型来执行此操作。

开发您的系统由外而内,并通过关注它们需要实现的行为来定义您的高级函数。使他们高阶函数通过传入依赖项作为参数。

需要查询数据存储?传入一个loadUser争论。需要保存用户吗?传入一个saveUser争论:

let myHighLevelFunction loadUser saveUser (userId) =
    let user = loadUser (UserId userId)
    match user with
    | Some u ->
        let u' = doSomethingInterestingWith u
        saveUser u'
    | None -> ()

The loadUser参数被推断为类型User -> User option, and saveUser as User -> unit, 因为doSomethingInterestingWith是类型的函数User -> User.

您现在可以“实施”loadUser and saveUser通过编写调用较低级别库的函数。

我对这种方法的典型反应是:这将要求我向我的函数传递太多参数!

事实上,如果发生这种情况,请考虑这是否是该函数试图做太多事情的味道。

自从依赖倒置原则 https://en.wikipedia.org/wiki/Dependency_inversion_principle这个问题的标题中提到了,我想指出的是坚实的原则 https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)如果所有这些都协同应用,效果最佳。这接口隔离原则 https://en.wikipedia.org/wiki/Interface_segregation_principle说接口应该尽可能小,并且你不会让它们比每个“接口”都是单个函数时更小。

有关描述此技术的更详细文章,您可以阅读我的类型驱动开发文章 http://blog.ploeh.dk/2015/08/10/type-driven-development.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

函数式编程和依赖倒置:如何抽象存储? 的相关文章

  • android-ndk 位于哪里?

    我安装了 Visual Studio 2017 在安装程序菜单中 我安装了 Xamarin 和 Visual C 但是 当我创建一个新项目时 转到 工具 gt 选项 gt Xamarin 我看到 android ndk 文本框为空 而其他文
  • 如何在 F# 中使用 LINQ 更新数据库中的表?

    我看过很多有关如何查询数据库的示例 但没有看到有关如何更新记录的示例 下面是我编写的用于检索表的简单代码 但有人可以解释一下如何修改字段 例如lastActiveDate 并更新数据库上的表 谢谢你 周日 open System open
  • Xamarin 构建错误:错误 APT0000:在 ...中,无法找到属性

    我收到了另一位开发商的项目 我设置了我的机器 带有所需组件的 VS 2017 已配置 Android SDK Manager已安装相应版本 项目配置为编译Android 7 1 Nougat 开始构建时出现一个错误 1 gt ERROR e
  • 通过 WCF 提供类对象的数组或列表

    任何提供自定义类对象列表或数组的 WCF 客户端服务器示例都会对我有所帮助 但这是我到目前为止所得到的 这是我想提供的班级系统 namespace NEN Server FS Serializable public class XFS pr
  • xaml.cs 文件上的 InitializeComponent() 出现错误

    有时我会收到一个红色错误 内容如下 InitializeComponent 在当前上下文中不存在 以及我的其他变量 xaml受约束的x Name The x ClassXaml 文件中的名称空间和类名确实对应于我的xaml cs file
  • Android:永久保存文件(即使在清除数据/卸载后)

    我想知道是否有一种方法可以永久存储少量数据 永久我的意思是即使用户清除应用程序数据 卸载应用程序 我也希望数据保留下来 我知道当用户清除应用程序数据 卸载应用程序时 共享首选项和数据库将被删除 我也知道我可以在 SD 卡上保存内容 但是如果
  • 是否可以使用 fparsec 解析“越位”(基于缩进)语言?

    我希望将 FParsec 用于基于缩进的类似 python 的语言 我知道这必须在词法分析阶段完成 但 FParsec 没有词法分析阶段 是否可以使用 FParsec 或者 词法分析后如何提供它 P D 我是 F 新手 但在其他语言方面经验
  • 为什么在这个函数定义中像这样使用“window.angular”?

    我正在尝试理解一个我需要用来与 Django 集成的 angularjs 文件 它有一个我不熟悉的奇怪语法 请记住我是一名初级开发人员 所以这可能是你的面包和黄油 它是这样的 function angular undefined use s
  • .Net 中可用的并行技术

    我是 Net 平台的新手 我查了一下 发现 Net中有几种做并行计算的方法 任务并行库中的并行任务 即 Net 3 5 PLINQ Net 4 0 异步编程 Net 2 0 异步主要用于执行 I O 繁重的任务 F 有简洁的语法支持这一点
  • int -> int list 与类型 int -> IEnumerable<'a> 不兼容

    Given open System Linq 这是一个可以接受的表达方式 2 3 4 SelectMany fun n gt 1 n 但这不是 2 3 4 SelectMany fun n gt 1 n 错误消息显示 int gt int
  • 如何运行传递给模拟方法的 lambda 函数?

    我想知道是否可以运行作为参数传递给模拟函数的 lambda 函数 并在调用模拟方法时运行它 我正在使用 Mockk 我想象代码是这样的 class DataManager fun submit lambda Int gt Unit val
  • 如何在 F# 中实现返回 void 的接口成员

    想象一下 C 中的以下接口 interface IFoo void Bar 我如何在 F 中实现这一点 我在 30 分钟的在线搜索中找到的所有示例都仅显示具有返回类型的示例 我认为这在函数式风格中更常见 但在这种情况下我无法避免 这是我到目
  • 将类型传递给通用 Swift 扩展,或者理想情况下推断它

    说你有 class Fancy UIView 你想找到所有兄弟姐妹Fancy意见 没问题 https stackoverflow com q 37232743 294884 for v UIView in superview subview
  • 闭包作为数据合并习惯的解决方案

    我正在尝试解决闭包问题 而且我think我发现了一个案例 他们可能会有所帮助 我有以下几部分需要处理 一组正则表达式 旨在清理状态名称 位于函数中 具有州名称 上述函数创建的标准化形式 和州 ID 代码的 data frame 用于链接两者
  • .NET 的 BLOB 分布式存储?

    我正在寻找一个经过相当好的测试的库 服务器来存储持久的分布式哈希表 我对使用基于 SQL 的解决方案犹豫不决 因为数据是高度面向文档的 由数百万个约 64KB 的 blob 组成 只有一个索引 由所述 BLOB 的哈希计算 并且需要能够进行
  • Xamarin.Forms 按钮的内容

    我正在尝试将自定义内容添加到 Xamarin Forms 中的按钮 默认情况下 按钮是这样创建的
  • 汉堡菜单棱镜xamarin形式?

    我正在尝试在 Xamarin Forms 中使用 Prism 创建一个应用程序 Xamarin 表单版本 2 3 3 175 棱镜版本 6 2 0 汉堡菜单可以在 Android 中使用 但是当我在 UWP 上运行它时 它不会显示图标 而且
  • 如何在Java 8中实现Elvis运算符?

    我有一个经典的 Elvis 运算符 案例 其中我调用每个可能返回 null 的方法并将它们链接在一起 thing nullableMethod1 a nullableMethod2 b nullableMethod3 在 Java 8 中
  • F# 查询,按单列对多个值进行分组

    我有一个 F sql 查询 需要对每组中的两列求和 let financials query for data in dbData do groupValBy data earning data losses data store into
  • 点击当前选项卡刷新页面时的 Xamarin.Forms TabbedPage 事件

    我正在使用 Xamarin Forms 构建 iOS Android 应用程序 并有一个 TabbedPage 如果用户已经在选项卡 2 上 并且单击了选项卡 2 并且我希望刷新选项卡 2 或者运行我自己的函数 以便我可以自己刷新它 有没有

随机推荐

  • hibernate 6.0.0.Final 自定义方言不再工作

    我正在使用 PostgreSQL 12 和 Hibernate 5 6 8 以及自定义方言 例如 registerFunction hstore find new SQLFunctionTemplate StandardBasicTypes
  • Java中如何安排周期性任务?

    我需要安排一个任务以固定的时间间隔运行 我怎样才能在长间隔 例如每 8 小时 的支持下做到这一点 我目前正在使用java util Timer scheduleAtFixedRate Does java util Timer schedul
  • 仅针对 Tab 和 Enter 自动完成

    在这种情况下如何禁用自动完成 Pressing after Rate autocomplets with DeviceRotationRate as displayed 我只想使用 Tab 或 和 Enter 进行自动完成 所以我会知道会发
  • 使用 EPPlus 加载大量 Excel 数据

    我有一个基本的 winforms 应用程序 用户可以上传 excel 文件 xlsx 并且我想读取该文件的内容 因此我使用 EPPlus 问题是 我正在尝试加载一个非常大的 Excel 文件的内容 它有 7 个选项卡 其中一个选项卡有超过
  • 如何解决异常 在 laravel 5.5 中运行 Dusk 是不安全的?

    我将我的项目从 laravel 5 4 升级到 laravel 5 5 我在本地环境中没有任何问题 但在服务器中我收到此异常 我搜索了很多 我知道这个问题可能会重复 但没有解决方案解决我的问题 当环境是生产环境时 如何不注册黄昏 我在 Ap
  • 函数调用中的新运算符

    我的问题是分配的对象会发生什么new函数调用内部的运算符 一个具体的例子 我有一个私有向量pV我想将其发送到类之外的对象 函数 foo gt func std vector
  • 是否可以使用 Epplus 在 Excel 中复制行(包含数据、合并、样式)?

    问题是我需要使用整个集合的单个模板将集合中的数据多次插入 Excel 中 using var pckg new ExcelPackage new FileInfo association TemplatePath var workSheet
  • 获取数据表列数据类型

    DataTable dt new DataTable dt Columns Add new DataColumn gridColumn1 typeof bool 我期望以下行的结果包含有关 DataColumns 类型 布尔 的信息 dt
  • 如何在While循环中有两个条件?

    基本上我的代码中有两个 while 循环 它们所做的只是从 0 到 10 或 10 以 1 为增量进行计数 计数向量是 count1 和 count2 这发生在我的代码中的两个单独的 while 循环中 但是 我现在需要每个计数相互依赖 因
  • Twitter API 是否允许按用户名和主题标签进行过滤?

    我可以获取特定用户使用特定主题标签的所有推文吗 我可以只获取过去 100 条推文 然后在我这边进行过滤 但如果 Twitter 可以在他们这边进行过滤 那就方便多了 这可能吗 Twitter 的高级搜索 http search twitte
  • 使用 MockMvc 获取 httpServletRequest 属性

    我有一个非常简单的控制器 以这种方式定义 RequestMapping value api test method RequestMethod GET produces application json public ResponseBod
  • 如何用Java绕点旋转多边形?

    我正在创建一个 Canvas 对象 直线 顶点 三角形 我想对它们应用围绕点的旋转 我无法使用 Canvas 的rotate 方法 因为点附加到地图上的GeoPoint 所以如果我使用rotate 方法 所有地图都会旋转 问题是 Canva
  • Django 管理内联表单 - 将外键查询集限制为一组值

    我有一些相互关联的模型需要在单个管理页面上共存 想法是这样的 戏剧作品有演员 演员有特定的角色 戏剧作品与给定的书面文本 戏剧 改编等 相关 并且书面文本包含该文本的所有角色的列表 添加作品时 每个演员都需要与这些角色之一关联 数据模型的工
  • Rails:文件路径

    我里面有app一个名为csv在这个目录中我有一个名为names csv我想用File read path string 函数来读取文件 文件的相对路径是什么 file File join Rails root app csv names c
  • 将当前时间添加到日期时间?

    我有一个代表日期的字符串 它从 DropDownList 中返回 该字符串是 2010 年 8 月 27 日 例如 现在我想将当前时间添加到此并将其解析为 Datetime 所以最终它应该是一个 DateTime 类似2010年8月27日
  • 如何使用 ts.transform 将附加语句注入到函数中

    我使用 Typescript 编译器 API ts transform ts updateFunctionDeclaration 在现有源文件中的函数开头注入附加语句 这非常有效 除了当我打印转换后的代码 使用 ts Printer 时 原
  • Dart - 将纪元以来的毫秒数(UNIX 时间戳)转换为人类可读的时间

    有没有一种好方法可以将纪元 例如 1486252500000 13 位 以来的毫秒数格式化为人类可读的格式 DateTime自纪元以来确实有一个毫秒的命名构造函数 https api dartlang org stable 1 24 2 d
  • 命名方法规则简单,兼容ARC命名约定

    我很难理解 ARC 的命名约定 我一直使用 ARC 进行编码 我想这就是原因 1 类方法 我应该为以下方法选择什么名称 这两个名称在内存管理方面有什么区别 这个名字 MyObject newObjectFrom MyObject anObj
  • 将 python 脚本的输出获取到 Jenkinsfile 中的变量中

    我有一个 Python 脚本 它在标准输出上返回一个字符串 python 脚本返回的值可以收集在 bash 脚本中 如下所示 bin bash outputString my python script py some parameter
  • 函数式编程和依赖倒置:如何抽象存储?

    我正在尝试创建一个具有较低级别库的解决方案 该库将知道在调用某些命令时需要保存和加载数据 但保存和加载函数的实现将在特定于平台的项目中提供它引用较低层的库 我有一些模型 例如 type User UserID UserID Situatio