c#函数式编程 Functional Programming in C# [23]

5.3 编程工作流程

  工作流是理解和表达应用需求的一种强有力的方式。一个工作流程是一个有意义的操作序列,导致一个期望的结果。例如,一个烹饪食谱描述了准备一道菜的工作流程。
  工作流可以通过函数组合来有效建模。工作流中的每个操作都可以由一个函数来执行,这些函数可以被组合成执行工作流的函数管道–就像你在前一个涉及数据在LINQ查询中流经不同转换的例子中看到的那样。
  我们现在要看的是一个更复杂的服务器处理指令的工作流程。这个场景是一个用户要求通过科德兰银行(BOC)的网上银行应用程序进行汇款。 我们只专注于服务器端,所以当服务器收到转账请求时,工作流就会启动。我们可以写下工作流程的规范,如下:

  1. 验证请求的传输。
  2. 加载帐户。
  3. 如果账户有足够的资金,从账户中扣款。
  4. 保留对帐户的更改。
  5. 通过 SWIFT 网络电汇资金。
5.3.1 一个简单的验证工作流程

  整个汇款工作流程是相当复杂的,所以为了让我们开始,让我们把它简化如下:

  1. 验证请求的传输。
  2. 预订转换服务(所有后续步骤)。

  也就是说,假设验证之后的所有步骤都是实际预订转账的子工作流程的一部分–当然,只有当验证通过时才会被触发(见图5.3)。

在这里插入图片描述
  让我们试一试实现这个非常高级的工作流程。假设服务器使用ASP.NET Core来暴露一个HTTP API,并且它被设置为请求区域经过认证并被路由到适当的MVC控制器,使其成为实现工作流的入口点。

using Microsoft.AspNetCore.Mvc;
public class MakeTransferController: Controller {
    IValidator < MakeTransfer > validator;
    [HttpPost, Route("api/MakeTransfer")] //对此路由的 POST 请求将路由到此方法。
    public void MakeTransfer
    	([FromBody] MakeTransfer transfer) {//请求正文将被反序列化为 MakeTransfer。
      if (validator.IsValid(transfer)) 
      	Book(transfer);
    }
    void Book(MakeTransfer transfer) 
    	=> // actually book the transfer...
}

  关于请求转移的细节被捕获在一个MakeTransfer类型中,它被发送到用户请求的主体中。验证被委托给一个控制器所依赖的服务,该服务实现了这个接口:

public interface IValidator<T>{
	bool IsValid(T t);
}

  现在到了有趣的部分,工作流程本身:

public void MakeTransfer([FromBody] MakeTransfer transfer)
{
	if (validator.IsValid(transfer))      
	Book(transfer);
}
void Book(MakeTransfer transfer)
   => // actually book the transfer...

  这就是显式控制流的命令式方法。我对使用ifs总是非常警惕:一个单一的if可能看起来无害,但如果你开始允许一个if,就没有什么能阻止你在额外的需求到来时有几十个嵌套的if,而随之而来的复杂度是使应用程序容易出错和难以推理的原因。
  接下来,我们将看看如何改用函数组合。

5.3.2 重构时考虑数据流

  还记得我们关于数据流经各种函数的想法吗?让我们试着把转移请求想象成数据流经验证并进入将执行转移的Book方法。图5.4显示了这样的情况。
在这里插入图片描述
  在类型上有一点问题。 IsValid返回一个布尔值,而Book则需要一个MakeTransfer对象,所以这两个函数不能合成,如图5.5所示。
在这里插入图片描述
  此外,我们需要确保请求数据流经验证,如果它通过了验证,则只进入Book。这就是Option可以帮助我们的地方:我们可以用None表示一个无效的转移请求,用Some< MakeTransfer >表示一个有效的请求。
  请注意,我们这样做是在扩展我们赋予Option的含义:我们把Some不仅用来表示数据的存在,而且还用来表示有效数据的存在,就像我们在智能构造函数模式中所做的那样。
  我们现在可以像这样重写控制器方法。

清单 5.4 使用Option来表示通过/失败的验证

public void MakeTransfer([FromBody] MakeTransfer transfer)
   => Some(transfer)
      .Where(validator.IsValid)
      .ForEach(Book);
void Book(MakeTransfer transfer)
	=> // actually book the transfer...

  我们将传输数据提升到一个 Option 中,并通过 Where 应用 IsValid 谓词;如果验证失败,这将产生一个 None,在这种情况下 Book 将不会被调用。在这个例子中,Where是一个高度可组合的函数,它允许我们把所有的东西粘在一起。这种风格可能不太熟悉,但它实际上是非常可读的。“如果有效的话,就保留这个转换,然后预订它”。

5.3.3 组合带来更大的灵活性

  一旦你有了一个工作流程,就很容易做出改变,比如给工作流程增加一个步骤。假设你想在验证请求之前对其进行规范化处理,这样像空格和大小写就不会导致验证失败。
  你将如何去做呢?你只需要定义一个执行新步骤的函数,然后把它整合到你的工作流程中。

清单 5.5 向现有工作流添加新步骤

publicvoid MakeTransfer([FromBody] MakeTransfer transfer)
   => Some(transfer)
      .Map(Normalize) //将新步骤插入工作流程。
      .Where(validator.IsValid)
      .ForEach(Book);
      
MakeTransfer Normalize(MakeTransfer request) => // ...

  更一般地说,如果你有一个业务工作流程,你应该通过组合一组函数来表达它,其中每个函数代表工作流程中的一个步骤,而它们的组合代表工作流程本身。 图5.6显示了这种从工作流程中的步骤到管道中的函数的一对一转换。
在这里插入图片描述
  接下来,让我们看看如何实现工作流程的其余部分。

Take advantage of the growing trend in functional programming. C# is the number-one language used by .NET developers and one of the most popular programming languages in the world. It has many built-in functional programming features, but most are complex and little understood. With the shift to functional programming increasing at a rapid pace, you need to know how to leverage your existing skills to take advantage of this trend. Functional Programming in C# leads you along a path that begins with the historic value of functional ideas. Inside, C# MVP and functional programming expert Oliver Sturm explains the details of relevant language features in C# and describes theory and practice of using functional techniques in C#, including currying, partial application, composition, memoization, and monads. Next, he provides practical and versatile examples, which combine approaches to solve problems in several different areas, including complex scenarios like concurrency and high-performance calculation frameworks as well as simpler use cases like Web Services and business logic implementation. Shows how C# developers can leverage their existing skills to take advantage of functional programming Uses very little math theory and instead focuses on providing solutions to real development problems with functional programming methods, unlike traditional functional programming titles Includes examples ranging from simple cases to more complex scenarios Let Functional Programming in C# show you how to get in front of the shift toward functional programming.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值