在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
背景在程序开发中,我们总是希望能够更加简洁、更加语义化地去表达自己的逻辑,链式调用是一种常见的处理方式。我们常用的 Masonry、 Expecta 等第三方库就采用了这种处理方式。 像这种用于特定领域的表达方式,我们叫做 DSL (Domain Specific Language),本文就介绍一下如何实现一个链式调用的 DSL. 链式调用的实现我们举一个具体的例子,比如我们用链式表达式来创建一个 UIView,设置其 frame、backgroundColor, 并添加至某个父 View。 1. 从语法层面来看链式调用可以用两种方式来实现: 在返回值中使用属性来保存方法中的信息 比如,Masonry 中的 再比如,Expecta 中的方法 再比如,上例中的 .with 方法,我们可以直接 使用 block 类型的属性来接受参数 比如 Masonry 中的 比如例子中的 在调用 2. 从语义层面来看从语义层面上,需要界定哪些是助词,哪些是需要接受参数的。为了保证链式调用能够完成,需要考虑传入什么,返回什么。 还是以上面的例子来讲:分步来看一下,这个 DSL 表达式需要描述的是一个祈使句,以 Alloc 开始,以 intoView 截止。在 intoView 终结语之前,我们对 UIView 进行一定的修饰,利用 下面我们分别从四段来看,如何实现这样一个表达式: (1) 宾语在 AllocA(UIView) 的语义中,我们确定了宾语是 a UIVIew。由于确定 UIView 是在 intoView 截止那时,所以我们需要创建一个中间类来保存所有的中间条件,这里我们用 ViewMaker 类。 另外我们可以注意到AllocA是一个函数,而UIView无法直接传递到这个函数中,语法就要变成 (2) 助词很多时候,为了让 DSL 的语法看起来更加连贯,我们需要一些助词来帮助,例如 Masonry 里面的 make.top.equalTo(superview.mas_top).with.offset(padding.top) 这句中的 with 就是这样一个助词。 而这个助词和我们学过的语法一样,通常没有什么实际效果,简单返回self就可以。 需要注意的是,返回自己,就没有办法阻止用户不断调用自己 这样就有效防止了, 不过使用类来区分助词还有另外几个小好处,就是它可以确保在语法提示的时候, 不过为了简化文章,我们都使用前者,既 (3) 修饰部分——定语像例子中的 我们来试着实现下: (4) 终结词“终结词”这个实在是在现代语法里面找不到对应关系了,但是在 DSL 中,这一段尤为重要。 在我们的例子里,终结词 这样,一个终结词就写好了。 最终代码的汇总: 总结这种链式调用能够使程序更加清晰,在特定场景下使程序的可读性更强。这种手段在Swift也是相同道理,大家可以善加利用,让自己的代码更加美观。 |
请发表评论