跳到内容
1.编程语言
1.1.仍然是一门语言
1.1.1.以最清晰、最容易理解的方式传递信息
1.2.代码的易读性和易理解性在软件中的重要性甚至更胜一筹
2.领域特定语言DSL
2.1.为了解决某个特定业务领域问题的一种自定义语言
2.1.1.一种小型语言
2.1.2.大多都不通用
2.1.3.为某个特定领域定制化而生
2.2.流畅式(fluent style)
2.2.1.链接(chaining)方法
2.3.别的底层实现细节都应该被隐藏
2.3.1.以这种方式设计的DSL才是一个用户友好的DSL
2.4.产生原因
2.4.1.沟通为王
2.4.1.1.代码应该能清晰地表达它的意图
2.4.1.2.被“非程序员”所理解
2.4.1.3.领域专家才能及时加入以验证代码是否符合业务需求
2.4.2.代码只编写一次,但会被阅读很多次
2.4.2.1.代码的可读性对软件的可维护性非常重要
2.5.资产
2.5.1.提升了你代码的抽象层次
2.5.2.使其能更加专注于业务目标
2.5.3.具有更好的可读性
2.6.负担
2.6.1.独立的代码需要测试和维护
2.7.优点
2.7.1.简洁
2.7.1.1.封装了业务逻辑
2.7.2.可读性
2.7.3.可维护性
2.7.4.高层的抽象性
2.7.5.专注
2.7.5.1.专门为表述业务领域规则而设计的语言
2.7.6.关注点隔离
2.7.6.1.使用专用的语言描述业务逻辑使得与业务相关的代码可以同应用的基础架构代码相分离
2.8.缺点
2.8.1.设计比较困难
2.8.2.开发代价
2.8.2.1.一项长期投资
2.8.3.额外的中间层
2.8.3.1.避免带来性能问题
2.8.4.要掌握的语言
2.8.5.宿主语言的局限性
3.外部DSL
3.1.独立DSL(stand-alone DSL)
3.2.需要付出更大的代价
3.2.1.从无到有进行创建,其语法与宿主语言几乎完全无关
3.2.2.设计DSL的语法
3.2.3.实现解析器和执行器(evaluator)
4.内部DSL
4.1.需要暴露恰当的类和方法,以使代码的编写逻辑更流畅
5.“多语言DSL”(polyglot DSL)
5.1.介于内部DSL与外部DSL之间的解决方案
5.2.可以在JVM上运行另一种通用编程语言
5.2.1.Scala
5.2.2.Groovy
6.DSL模式
6.1.方法链接(method chaining)
6.1.1.需要实现非常冗长的构建器
6.1.2.为了将顶层构建器与底层构建器相融合,需要使用大量的胶水代码
6.2.嵌套函数DSL(nested function DSL)
6.3.使用Lambda表达式的函数序列
6.3.1.在DSL中使用方法引用
7.Java API中的小型DSL
7.1.把Stream API当成DSL去操作集合
7.1.1.可以对集合中的元素进行过滤、排序、转换、归并等操作
7.2.将Collectors作为DSL汇总数据
8.DSL的实际应用
8.1.SQL是最通用且应用最广泛的DSL
8.2.jOOQ
8.2.1.一种SQL映射工具
8.3.Cucumber
8.3.1.行为驱动开发(behavior-driven development, BDD)
8.3.2.一种基于行为驱动的开发框架
8.4.Spring Integration
8.4.1.一种实现企业集成模式的Spring扩展库
9.生成字节码
9.1.匿名类
9.1.1.编译器会为每个匿名类生成一个新的.class 文件
9.1.2.文件名通常以ClassName$1这种形式呈现
9.1.3.生成大量的类文件是不利的
9.1.3.1.直接影响应用的启动性能
9.1.4.每个新的匿名类都会为类或者接口产生一个新的子类型
9.2.Lambda表达式
9.2.1.InvokeDynamic
9.2.1.1.Java7
9.2.1.2.字节码指令
9.2.1.3.创建额外的类现在被invokedynamic指令替代了
9.2.1.4.用于支持运行于JVM上的动态类型语言
9.2.1.5.将实现Lambda表达式的这部分代码的字节码生成推迟到运行时
9.2.2.将Lambda表达式的代码体填入到运行时动态创建的静态方法,就完成了Lambda表达式的字节码转换
9.2.2.1.Lambda表达式的代码块到字节码的转换由高层的策略变成了纯粹的实现细节
9.2.2.2.对无状态非捕获型Lambda,可以创建一个Lambda对象的实例,对其进行缓存,之后对同一对象的访问都返回同样的内容
9.2.2.3.没有带来额外的开销,没有额外的字段,也不需要进行静态初始化
9.2.2.4.没有额外的性能开销,因为这些转换都是必须的,并且结果也进行了链接
9.2.2.4.1.仅在Lambda首次被调用时需要转换,其后所有的调用都能直接跳过这一步,直接调用之前链接的实现