我画着图,FluentAPI 她自己就生成了

在 Newbe.ObjectVistor 0.3 版本中我们非常兴奋的引入了一个紧张刺激的新特性:使用状态图来生成任意给定的 FluentAPI 设计。

开篇摘要

在非常多优秀的框架中都存在一部分 FluentAPI 的设计。这种 API 设计更加符合人类自言语言描述。使得代码更加具备可读性。

在 Newbe.ObjectVistor 0.3 版本中,我们设计引入了一种使用状态图来自动生成 FluentAPI 代码的机制。极大了简化了 FluentAPI 实现所需要的脑力劳动。

本篇我们将通过一些示例,来了解一下当前版本中该特性的主要效果。

整数累加 FluentAPI

假如,我们现在需要实现下面这样效果的一个 API:

[Test]
public void SumList()
{var sumBuilder = new SumBuilder(new List<int>());var re = sumBuilder.AddNumber(1).AddNumber(2).AddNumber(3).Sum();re.Should().Be(6);
}

这个 API 使用 FluentAPI 的方式来表述一个累加的过程。

为了实现这个 API 设计,在 Newbe.ObjectVisitor 0.3 中,使用下面这样一个状态图标记表述这个 API 设计:

stateDiagram[*]  --> AddNumber : AddNumber(int number)AddNumber  --> AddNumber : AddNumber(int number)AddNumber --> [*] : Sum() return int

这实际上是 mermaid 状态图标记。转换为图形即为下面这个效果。不需要过多的解释就可以理解:

SumBuilder

有了这个状态图之后,使用 Newbe.ObjectVisitor 中的 FluentApiDesignParserFluentApiFileGenerator 便可以生成如下代码。

using System;
using System.Collections.Generic;
using System.Linq;namespace Newbe.ObjectVisitor.Tests.SumBuilderFluentApi
{public class SumBuilder : Newbe.ObjectVisitor.IFluentApi, SumBuilder.ISumBuilder_AddNumber{private readonly List<int> _context;public SumBuilder(List<int> context){_context = context;}#region UserImplprivate void Core_AddNumber(int number){throw new NotImplementedException();}private int Core_Sum(){throw new NotImplementedException();}#endregion#region AutoGenerate
/// 此处省略了自动生成的固定代码部分,请到仓库中查看#endregion}
}

有了这个模板之后,只要实现 Core_AddNumberCore_Sum,一个符合预期设计的 FluentAPI 就完成了!

累加后累乘

现在,我们稍微改变一下需求。上节我们实现的是一个 1+2+3 这样的累加效果。现在我们需要一个 (1+2+3)*(4+5+6)*(7+8+9+10) 这样的效果。

示例的调用代码如下:

[Test]
public void MultipleSumList()
{var builder = new MultipleSumBuilder(new List<List<int>>());var re = builder.AddNumber(1).AddNumber(2).NextFactor().AddNumber(3).Sum();re.Should().Be(9);
}

为了实现这个效果,我们修改一下状态图,增加一条新的规则,得到:

stateDiagram[*]  --> AddNumber : AddNumber(int number)AddNumber  --> AddNumber : AddNumber(int number)AddNumber  --> AddNumber : NextFactor()AddNumber --> [*] : Sum() return int

如图:

MultipleSumBuilder

创建数据库链接字符串

前面的示例或许缺乏生产实际,现在添加一个生产示例。我们现在要实现一个 ConnectionStringBuilder 用来创建数据库连接字符串,其中有以下限制:

  1. 必须指定 Host。

  2. 身份认证方式必须且只能指定一种,要么是用户名密码方式,要么是 Windows 凭据。

首先,我们有一个模型来保存上面提到的数据。

public class ConnectionStringModel
{public string Host { get; set; }public string Username { get; set; }public string Password { get; set; }public bool? IsWindowsAuthentication { get; set; }
}

接着,我们直接使用状态图来设计这个 FluentAPI。设计结果如下:

stateDiagram[*]  --> SetHost : SetHost(string host)SetHost  --> UseUsernamePassword : UseUsernamePassword(string username, string password)SetHost  --> UseWindowsAuthentication : UseWindowsAuthentication()UseUsernamePassword --> [*] : Build() return stringUseWindowsAuthentication --> [*] : Build() return string

如图:

ConnectionStringBuilder

有了设计,接下来就是使用生成器啪嗒一下生成代码,然后添加实现,这里只展示需要自己实现的内容:

#region UserImplprivate void Core_SetHost(string host)
{_context.Host = host;
}private void Core_UseUsernamePassword(string username, string password)
{_context.Username = username;_context.Password = password;
}private void Core_UseWindowsAuthentication()
{_context.IsWindowsAuthentication = true;
}// 这里使用 ObjectVisitor 将一个模型的非空字段拼接在一起
private static readonly ICachedObjectVisitor<ConnectionStringModel, StringBuilder> Builder =default(ConnectionStringModel)!.V().WithExtendObject<ConnectionStringModel, StringBuilder>().ForEach((name, value, sb) => Append(name, value, sb)).Cache();private static void Append(string name, object? value, StringBuilder sb)
{if (value != null){sb.Append($"{name}={value};");}
}private string Core_Build()
{var sb = new StringBuilder();Builder.Run(_context, sb);return sb.ToString();
}#endregion

下面是简单的两个测试用例:

public class ConnectionStringBuilderTest
{[Test]public void UseUsernamePassword(){var builder = new ConnectionStringBuilder(new ConnectionStringModel());var re = builder.SetHost("localhost").UseUsernamePassword("yueluo", "dalao").Build();re.Should().Be("Host=localhost;Username=yueluo;Password=dalao;");}[Test]public void UseWindowsAuthentication(){var builder = new ConnectionStringBuilder(new ConnectionStringModel());var re = builder.SetHost("localhost").UseWindowsAuthentication().Build();re.Should().Be("Host=localhost;IsWindowsAuthentication=True;");}
}

值得特别提出但是,这和直接使用 ConnectionStringModel 模型来构建字符串,通过 FluentAPI 的形式,约束了开发者能够赋值的属性。可以避免忘记对必要的属性赋值或者错误赋值等等出错情况。

Get 和 Delete 没有 Body,Post 和 Put 才有

和上一节类型,我们使用 FluentAPI 来构建请求,但是需要满足以下约束:

  1. 可以指定 Uri

  2. Get 和 Delete 不能指定 Body,但是 Post 和 Put 可以

上设计:

stateDiagram[*]  --> Get : Get()Get --> GetUri : SetUri(Uri uri) share _SetUriCore[*]  --> Delete : Delete()Delete --> DeleteUri : SetUri(Uri uri) share _SetUriCore[*]  --> Post : Post()Post --> PostUri : SetUri(Uri uri) share _SetUriCorePostUri --> SetContent : _SetContent share _SetContentCore[*]  --> Put : Put()Put --> PutUri : SetUri(Uri uri) share _SetUriCorePutUri --> SetContent : _SetContent share _SetContentCoreSetContent --> [*] : _Build return HttpRequestMessageGetUri --> [*] : _Build return HttpRequestMessageDeleteUri --> [*] : _Build return HttpRequestMessage

上图:

RequestBuilder

注意,这里引入了一些奇怪的关键词 share ,由于这些关键词还未全部定稿,因此不展开说明。

可以通过以下链接,查看生成的代码和测试用例。

https://github.com/newbe36524/Newbe.ObjectVisitor/tree/main/src/Newbe.ObjectVisitor/Newbe.ObjectVisitor.Tests/HttpClientFluentApi

https://gitee.com/yks/Newbe.ObjectVisitor/tree/main/src/Newbe.ObjectVisitor/Newbe.ObjectVisitor.Tests/HttpClientFluentApi

造一辆汽车一定要四个轮子一个引擎

我们需要实现一个 CarBuilder,有一些约束:

  1. CarBuilder 当且仅当在调用四次 AddWheel 和一次 AddEngine 之后才能出现 Build 方法

  2. 虽然限制了次数,但是,顺序不能限定,什么顺序都可以。

上设计:

stateDiagram[*]  --> W1 : AddWheel(int size) share AddWheelW1 --> W2 : AddWheel(int size) share AddWheelW2 --> W3 : AddWheel(int size) share AddWheelW3 --> W4 : AddWheel(int size) share AddWheel[*] --> E : AddEngine(string engine) share AddEngineE --> WE1 : AddWheel(int size) share AddWheelWE1 --> WE2 : AddWheel(int size) share AddWheelWE2 --> WE3 : AddWheel(int size) share AddWheelWE3 --> WE4 : AddWheel(int size) share AddWheelW1 --> WE1 : AddEngine(string engine) share AddEngineW2 --> WE2 : AddEngine(string engine) share AddEngineW3 --> WE3 : AddEngine(string engine) share AddEngineW4 --> WE4 : AddEngine(string engine) share AddEngineWE4 --> [*] : Build() return Car

上图,这个图从出发点出发,不论怎么走都会经过四次 AddWheel 和 一次 AddEngine:

CarBuilder

注意,虽然设计看起来非常复杂,但是,需要手写的代码只有非常简短的两段:

#region UserImplprivate void Shared_AddWheel(int size)
{if (_context.Wheel1 == 0){_context.Wheel1 = size;return;}if (_context.Wheel2 == 0){_context.Wheel2 = size;return;}if (_context.Wheel3 == 0){_context.Wheel3 = size;return;}if (_context.Wheel4 == 0){_context.Wheel4 = size;return;}
}private void Shared_AddEngine(string engine)
{_context.Engine = engine;
}private Car Core_Build()
{return _context;
}#endregion

可以通过以下链接,查看生成的代码和测试用例。

https://github.com/newbe36524/Newbe.ObjectVisitor/tree/main/src/Newbe.ObjectVisitor/Newbe.ObjectVisitor.Tests/CarBuilder

https://gitee.com/yks/Newbe.ObjectVisitor/tree/main/src/Newbe.ObjectVisitor/Newbe.ObjectVisitor.Tests/CarBuilder

本篇总结

这是一个很有意思的设计,如果你对这个设计很感兴趣,有新奇的想法,欢迎关注 Newbe.ObjectVisitor 项目,提出您的宝贵想法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306922.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python的基础知识可以应用到哪方面-Python基础知识

python基础 python的诞生 2002年&#xff0c;python 2.x 2008年&#xff0c;python 3.x python的命名 马戏团的名称 python简介 简单、易学 持快速开发. 跨平台. 开源. 可扩展. 可嵌入. 大量的标准库和活跃的交流群. 可用于各种各样的开发. 应用领域 系统编程 提供API&#xff…

java爬虫基础知识,Java网络爬虫基础知识

引言Java 网络爬虫具备很好的扩展性可伸缩性&#xff0c;其是目前搜索引擎开发的重要组成部分。例如&#xff0c;著名的网络爬虫工具 Nutch 便是采使用 Java 开发&#xff0c;该工具以 Apache Hadoop 数据结构为依托&#xff0c;提供了良好的批解决支持。Java 网络爬虫涉及到 J…

.NET5都来了,你还不知道怎么部署到linux?最全部署方案,总有一款适合你

随着2020进入4季度&#xff0c;.NET5正式版也已经与大家见面了。不过&#xff0c;尽管 .NET Core发布已经有四五年的时间&#xff0c;但到目前为止&#xff0c;依旧有很多.NET开发者在坚守者.NET4&#xff0c;原因不尽相同&#xff0c;但最大的问题可能还是不熟悉Linux&#xf…

好用的平板电脑_平板选择华为M6,这里有几点建议

大家好&#xff0c;我是师兄。平板几乎已经成大学生生活中必备的物品之一了&#xff0c;现在的学生实在是太会享受了。作为华为M6的重度使用用户&#xff0c;在这里给大家在购买华为平板M6时提几点建议。1.质量挺好的&#xff0c;品制有保证购买华为平板M6已经半年了&#xff0…

读取oracle bfile字段,ORACLE中BFILE字段的使用研究_oracle

因为做项目&#xff0c;需要使用BFILE字段存储图像文件&#xff0c;所以进行了一些研究。bfile字段实际的文件存储在文件系统中,字段中存储的是文件定位指针.bfile对oracle来说是只读的,也不参与事务性控制和数据恢复bfile的基本操作如下&#xff1a;1.先在oracle数据库中下面我…

客户的一个紧急bug,我用了两种方式进行 C# 反编译修改源码

一&#xff1a;背景 1. 讲故事周五下午运营反馈了一个紧急bug&#xff0c;说客户那边一个信息列表打不开&#xff0c;急需解决&#xff0c;附带的日志文件也发过来了&#xff0c;看了下日志大概是这样的&#xff1a;日期:2020-11-13 12:25:45,923 线程ID:[3924] 日志级别:INFO …

离线语音识别软件_从音乐识别软件起家,这家公司如何备战车载AI语音市场GGAI对话...

加入高工智能汽车专业行业群(自动驾驶5群&#xff0c;车联网智能座舱3群&#xff0c;智能网联商用车2群)&#xff0c;加微信&#xff1a;17157613659&#xff0c;出示名片&#xff0c;仅限智能网联汽车软硬件供应商及OEM厂商。早在2016年&#xff0c;亚马逊推出的语音助手Alexa…

int函数在Oracle,vb中int是什么意思 ?

VB语言中int函数的意思是取整数。即&#xff1a;int(x)函数是取不大于x的最大整数。例如&#xff1a;1、int(4.88)4int(4.88)即是取一个不大于4.88且最接近4.88的整数&#xff0c;所以int(4.88)4。2、int(8.1)8int(8.1)即是取一个不大于8.1且最接近8的整数&#xff0c;所以int(…

.NET 5 中的隐藏特性

转自&#xff1a;hez2010cnblogs.com/hez2010/p/13963803.html前言双十一当天&#xff0c;个人觉得非常香&#xff0c;并且花了 10 分钟时间就把自己的 4 个 .NET Core 3.1 的项目升级到了 .NET 5&#xff0c;堪称无痛。但是&#xff0c;.NET 5 中还有一些没有正式公开的隐藏特…

windows如何添加本机dns记录_运维必看!超清晰的 DNS 原理入门指南

来源&#xff1a;阮一峰的网络日志作者&#xff1a;阮一峰链接&#xff1a;http://www.ruanyifeng.com/blog/2016/06/dns.htmlDNS 是互联网核心协议之一。不管是上网浏览&#xff0c;还是编程开发&#xff0c;都需要了解一点它的知识。本文详细介绍DNS的原理&#xff0c;以及如…

linux oracle流复制,oracle 流复制

测试环境:oracle linux 虚拟机192.168.1.4,192.168.1.5oracle 10.2.0.3alter system set global_namestrue scopeboth;show parameter COMPATIBLEshow parameter jobalter system set streams_pool_size15 scopememory;[more]归档日志模式GRANT DBA TO strmadmin IDENTIFIED BY…

天际数见数据质量巡检架构优化

源宝导读&#xff1a;天际数见平台是一个数据可视化的BI平台&#xff0c;定位于为高层决策提供数据可视化赋能。数据准确性是生命线&#xff0c;如何提前发现数据问题&#xff0c;快速定位和修复问题&#xff0c;成为我们必须攻克的难点。本文将介绍数见平台通过架构优化&#…

db2 删除存储过程_蚂蚁金服OceanBase挑战TPCC | TPCC基准测试之存储优化

蚂蚁金服自研数据库 OceanBase 登顶 TPC-C 引起业内广泛关注&#xff0c;为了更清楚的展示其中的技术细节&#xff0c;我们特意邀请 OceanBase 核心研发人员对本次测试进行技术解读&#xff0c;共包括五篇&#xff1a;1)TPC-C基准测试介绍2)OceanBase如何做TPC-C测试3)TPC-C基准…

Github Actions 中 Service Container 的使用

Github Actions 中 Service Container 的使用Intro之前写过一个 StackExchange.Redis 的一个扩展&#xff0c;测试项目依赖 redis&#xff0c;所以之前测试一直只是在本地跑一下&#xff0c;最近通过 Github Action 中的 Service Container 来通过 CI 来跑测试&#xff0c;分享…

php的web能力,web 性能的几个概念。

每秒查询率QPS&#xff1a;对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准&#xff0c;即每秒请求数&#xff0c;即最大谈吐能力。并发数&#xff1a;并发数和QPS是不同的概念&#xff0c;一般说QPS会说多少并发用户下QPS&#xff0c;当QPS相同时&#xff0c;并发…

深度探秘.NET 5.0

2020 中国.NET 开发者峰会正式启动 &#xff0c;欢迎大家提交演讲主题或者购买超级早鸟票。今年11月10号 .NET 5.0 如约而至。这是.NET All in one后的第一个版本&#xff0c;虽然不是LTS(Long term support)版本&#xff0c;但是是生产环境可用的。微软从.NET 5 Preview 1就开…

vuex保存用户信息_Vuex状态管理

一个组件可以分为数据和视图&#xff0c;数据更新时&#xff0c;视图也会自动更新。在视图中又可以绑定一些事件&#xff0c;它们触发methods里面指定的方法&#xff0c;从而又可以改变数据、更新视图&#xff0c;这就是一个组件基本的运行模式。但实际的业务中&#xff0c;经常…

Linux 子进程限制,linux进程控制-waitpid()

waitpid系统调用在Linux函数库中的原型是&#xff1a;#include #include pid_t waitpid(pid_t pid,int *status,int options)从本质上讲&#xff0c;系统调用waitpid和wait的作用是完全相同的&#xff0c;但waitpid多出了两个可由用户控制的参数pid和options&#xff0c;从而为…

使用 docker 构建分布式调用链跟踪框架skywalking

一旦你的程序docker化之后,你会遇到各种问题&#xff0c;比如原来采用的本地记日志的方式就不再方便了&#xff0c;虽然你可以挂载到宿主机&#xff0c;但你使用 --scale 的话&#xff0c;会导致记录日志异常&#xff0c;所以最好的方式还是要做日志中心化&#xff0c;另一个问…

excel同一单元格怎么换行_excel表格内怎么换行 方法有两种 一看就会 新手教程...

很多人在用excel表格的时候都需要用到换行&#xff0c;但是有一些小伙伴还不知道如何去换行。今天就介绍两种单元格内换行的方法&#xff0c;这两种换行方式的效果不一样&#xff0c;大家可以根据自己的需求来选择使用哪种换行方式。方法一&#xff1a;单元格内自动换行操作&am…