使用DSL优雅的实现串口协议
来源:互联网 发布:淘宝的广告语 编辑:程序博客网 时间:2024/05/17 18:18
先看看效果
kotlin代码:
fun ledOnBoardInstruction(index: Byte, ledIndex: Byte, r: Short, g: Short, b: Short) = rj25Instruction { index(index) mode(modeWrite) command(commandLed) port(7) slot(2) data(ledIndex) data(r) data(g) data(b) }
这段代码的作用,是完成这样一条蓝牙串口协议:
协议需要的是动态计算的,长度不定的Byte数组,能写成这样,酷不酷炫,想不想学?
什么是DSL
Domain-specific language,领域特定语言,定义自行看维基百科,以下是我个人的总结:
求专不求全,所有的代码就是为了解决一个特定问题,以上面的代码为例,length是动态的,后面的每个字段的顺序也是不确定的,如果按Java的方式(作为一个Android开发,我说的显然不是Java8(╥﹏╥)),类会是这个样子:
现在是这样:
当然这也有kotlin允许在同一个文件定义多个类的原因,但DSL的方式,完全只考虑了协议本身,所以很多问题都迎刃而解- DSL不会减少你的工作量,甚至会造成稍多一些的开发工作量,但是多出来的工作量,换取别的好处,我认为是值得的
- 代码即文档,从例子的两张图就可以看出,代码与实际协议的字段,是一一对应的,只要定义好最基础的东西,随便谁接收,都可以很轻松的继续编写出可读性非常高的代码
具体怎么实现
- 首先,这其实是使用Lambda 表达式来构建Builder,所以Java8,或者其他支持Lambda 表达式的语言,也可以做到类似的事,只是可能没有kotlin这种立志成为语法糖语言的语言简洁~~
- Lambda 表达式如果不熟悉,可以参考Kotlin中文文档,下面在介绍的过程中也会逐步介绍
- rj25Instruction是一个函数,它接收的参数,是一个Lambda表达式,而kotlin中,如果最后一个参数为Lambda表达式,可以省略括号,直接接方括号写表达式:
fun rj25Instruction(init: Rj25Instruction.() -> Unit): Rj25Instruction { val rj25Instruction = Rj25Instruction() rj25Instruction.init() return rj25Instruction}
所以这段代码的作用为新建一个Rj25Instruction类,依次执行这个类的这些方法:
index(index)mode(modeWrite)command(commandLed)port(7)slot(2)data(ledIndex)data(r)data(g)data(b)
当然在这些之前,还有Rj25Instruction内部定义的初始化方法:
init { head() length()}
对照着文档,是不是一目了然?
- 内部的函数:
private fun head() = addChild(ArrayByteElement(headBytes))private fun length() = addChild(lengthElement)fun index(byte: Byte) { index = byte.toInt() addChild(ByteElement(byte))}fun mode(byte: Byte) = addChild(ByteElement(byte))fun command(byte: Byte) = addChild(ByteElement(byte))fun port(byte: Byte) = addChild(ByteElement(byte))fun slot(byte: Byte) = addChild(ByteElement(byte))fun secondaryCommand(byte: Byte) = addChild(ByteElement(byte))fun data(byte: Byte) = addChild(ByteElement(byte))fun data(int: Int) = addChild(IntElement(int))fun data(float: Float) = addChild(FloatElement(float))fun data(short: Short) = addChild(ShortElement(short))fun data(bytes: Array<Byte>) = addChild(ArrayByteElement(bytes))override fun getBytes(): ByteArray { calculateLength() return super.getBytes()}private fun calculateLength() { val length = getSize() - headBytes.size - lengthElement.getSize() lengthElement.data = length.toByte()}
更加深入的代码就没有必要贴出来了,也就是更进一步的转换数据而已,到这里可以很明显的看出实现DSL的思路了,使用Lambda 表达式来构建Builder,已经明白了吧?如果这都还不懂,建议温习下StringBuilder的用法~~
更多的应用场景
- 以我所在的项目为例,还有别的协议需要实现,比如协议字段多重校验,需要计算校验和,用DSL的方式可以更加优雅的实现
- HTML网页的输出,见官方的例子:HTML
- 对Android来说,书写UI布局:anko(这个其实我不推荐,不能预览的布局,不太适合真正的项目合作)
阅读全文
0 0
- 使用DSL优雅的实现串口协议
- 使用Antlr实现简单的DSL
- 我使用DSL编写SQL的一个Java实现
- 如何优雅的实现界面跳转 之 统跳协议
- 如何优雅的实现界面统跳协议
- 使用ServletContextListener实现优雅的系统初始化
- 使用ServletContextListener实现优雅的系统初始化
- DSL的实现要点(1)
- DSL的实现要点(2)
- ThreadLocal的优雅使用
- 优雅的使用ViewHolder
- 优雅的使用abstract
- INotifyPropertyChanged的优雅使用
- 优雅的使用mysql
- 优雅的使用optional
- RecycleView的优雅使用
- 优雅的使用DbContext
- 优雅的使用python
- 事务管理优秀资源整理
- Java中常见算法总结
- androidstdio自动注释
- EasyDSS RTMP流媒体服务器是怎样炼成的:Easy而且更加互联网!
- 百度百科人工智能整理
- 使用DSL优雅的实现串口协议
- 实验三
- 洛谷p2196挖地雷
- Java后端WebSocket的Tomcat实现
- HDU6153(KMP)
- 小程序跳转带多个参数
- 一维数组排序
- Windows10下安装caffe2 支持GPU和CPU
- 设计模式的艺术之道--观察者模式