1 3 7 - 1 4 4 1 - 9 7 9 7
首页 > 品牌伙伴 > 品牌伙伴详细内容

[北京网站建造]API设想新思维:用流通接口组织外部DSL

来源:网站优化 | 作者:网站优化 | 时间:2022-04-17 | 浏览:1454
字体大小:


API假想新思想:用流通接口结构外部DSL


法式假想措辞的笼统机制包括了两个最基础的方面:一是措辞存眷的基础元素/语义;另外一个是从基础元素/语义到复合元素/语义的结构法则。在C、C++、Java、C#、Python等通用措辞中,措辞的基础元素/语义常常离结果域较远,经由过程API库的情势停止层层笼统是下降结果难度最经常使用的方式。比如,在C措辞中最稀有的体式款式是供应函数库来封装庞杂逻辑,利便外部调用。(北京网站制作)


不过平凡的API假想方式存在一种自然的圈套,那就长短论如何封装,大过程虽然比小过程笼统层次更高,但素质上还是过程,遭到过程语义的限制。也就是说,经由过程基础元素/语义结构更高等笼统元素/语义的时辰,措辞的结构法则很大程度下限制了笼统的维度,我们很难跳出这个维度去,乃至能够基础认识不到这个限制。而SQL、HTML、CSS、make等DSL(范畴特定措辞)的笼统维度是为特定范畴量身定做的,从这些笼统角度当作绩常常最为简略,以是DSL在处理惩罚其特定范畴的结果时比通用法式假想措辞更加利便。常常,SQL等非通用措辞被称为外部DSL(External DSL);在通用措辞中,我们其实也可以在肯定程度上打破措辞结构法则的笼统维度限制,定义外部DSL(Internal DSL)。


本文将先容一种被称为流通接口(Fluent Interface)的外部DSL假想方式。Wikipedia上Fluent Interface的定义是:










A fluent interface (as first coined by Eric Evans and Martin Fowler) is an implementation of an object oriented API that aims to provide for more readable code. A fluent interface is normally implemented by using method chaining to relay the instruction context of a subsequent call (but a fluent interface entails more than just method chaining)。



下面将分4个部分来慢慢声明流通接口在结构外部DSL中的典范运用。


1.基础语义笼统


如果要输入0..4这5个数,我们普通会首先想到类似多么的代码:



  1. //Java

  2. for (int i = 0; i < 5; ++i) {

  3. system.out.println(i);

  4. }



而Ruby虽然也支持类似的for轮回,但最简略的是下面多么的完成:



  1. //Ruby

  2. .times {|i| puts i}


Ruby中统统皆工具,5是Fixnum类的实例,times是Fixnum的一个方式,它担当一个block参数。对比for轮回完成,Ruby 的times体式款式更精练,可读性更强,但熟谙OOP的朋侪能够会有疑问,times能否应该作为整型类的方式呢?在OOP中,方式调用常常代表了向工具发送新闻,改动或查询工具的形状,times方式明显不是对整型工具形状的查询和点窜。如果你是Ruby的假想者,你会把times方式放入Fixnum类吗?如果答案能否定的,那末Ruby的这类假想素质上代表了甚么呢?实际上,这里的times虽然只是一个平凡的类方式,但它的方针却与平凡意义上的类方式差别,它的语义实际上类似于for轮回多么的措辞基础语义,可以被视为一种自定义的基础语义。times的语义从肯定程度上跳出了类方式的框框,向结果域迈进了一步!


另外一个例子来自Eric Evans的“用两个时辰点结构一个时辰段工具”,平凡假想:



  1. 3 //Java

  2. TimePoint fiveOClock, sixOClock;

  3. TimeInterval meetingTime = new TimeInterval(fiveOClock, sixOClock);



另外一种Evans的假想是多么:



  1. 2 //Java

  2. TimeInterval meetingTime = fiveOClock.until(sixOClock);


按传统OO假想,until方式本不应出而今TimePoint类中,这里TimePoint类的until方式一样代表了一种自定义的基础语义,使得表达时辰域的结果更加自然。


虽然下面的两个简略例子和平凡假想对比看不出太大的下风,但它却为我们了解流通接口打下了根本。重要的是应该体味到它们从肯定程度上跳出了措辞基础笼统机制的束缚,我们不应该再用类职责分别、迪米特规律(Law of Demeter)等OO假想绳尺来对待它们。


2.管道笼统


在Shell中,我们可以经由过程管道将一系列的小敕令组合在一起完成庞杂的功效。管道中活动的是单一规范的文本流,较量争论过程就是从输入流到输入流的变卦过程,每一个敕令是对文本流的一次变卦浸染,经由过程管道将浸染叠加起来。在Shell中,很多时辰我们只需要一句话就能完成log统计多么的中小范畴结果。和其他笼统机制对比,管道的精美在于无嵌套。比以下面这段C法式,因为嵌套层次较深,不随便一会儿了解了了:



  1. 2 //C

  2. min(max(min(max(a,b),c),d),e)


而用管道来表达一样的功效则了了很多:




  1. 2 #!/bin/bash

  2. max a b | min c | max d | min e



我们很随便了解这段法式表达的意义是:先求a,b的最大值;再把结果和c取最小值;再把结果和d求最大值;再把结果和e求最小值。


jQuery的链式调用假想也具有管道的气势派头,方式链上活动的是同一规范的jQuery工具,每步方式调用是对工具的一次浸染,全部方式链将各个方式的浸染叠加起来。



  1. 2 //Javascript

  2. $('li').filter(':event').css('background-color', 'red');



3.层次结构笼统


除管道这类“线性”结构外,流通接口还可用于结构层次结构笼统。比如,用Javascript静态建立建立下面的HTML片断:



  1. <div id="’product_123’" class="’product’">

  2. <img src="’preview_123.jpg’" alt="" />

  3. <ul>

  4. <li>Name: iPad2 32Gli>

  5. <li>Price: 3600li>

  6. ul>

  7. div>



若采用Javascript的DOM API:



  1. //Javascript

  2. var div = document.createElement('div');

  3. div.setAttribute(‘id’, ‘product_123’);

  4. div.setAttribute(‘class’, ‘product’);


  5. var img = document.createElement('img');

  6. img.setAttribute(‘src’, ‘preview_123.jpg’);

  7. div.appendChild(img);


  8. var ul = document.createElement('ul');

  9. var li1 = document.createElement('li');

  10. var txt1 = document.createTextNode("Name: iPad2 32G");

  11. li1.appendChild(txt1);


  12. div.appendChild(ul);



而下面流通接口API则要有表示力很多:



  1. //Javascript

  2. var obj =

  3. $.div({id:’product_123’, class:’product’})

  4. .img({src:’preview_123.jpg’})

  5. .ul()

  6. .li().text(‘Name: iPad2 32G’)._li()

  7. .li().text(‘Price: 3600’)._li()

  8. ._ul()

  9. ._div();


和Javascript的尺度DOM API对比,下面的API假想不再范畴于孤立地对待某一个方式,而是斟酌了它们在处理惩罚结果时的组合运用,以是代码的表示情势出格切近结果的素质。多么的代码是自说明的(self-explanatory)在可读性方面要明显胜于DOM API,网站优化,这相当于定义了一种类似于HTML的外部DSL,它具有自己的语义和语法。需要出格留神的是,下面的层次结构笼统和管道笼统有着素质的差别,管道笼统的方式链上常常是同一工具的连气儿通报,而层次笼统中方式链上的工具却在随着层次的变化而变化。此为,我们可以把业务法则也表达在流通接口中,比如下面的例子中,body()不克不及包括在div()前去的工具中,div().body()将抛出”body方式不存在”非常。(高端网站扶植)


4.异步笼统


流通接口不但可以结构庞杂的层次笼统,还可以用于结构异步笼统。在基于回调机制的异步情势中,多个异步调用的同步和嵌套结果是运用异步的难点所在。有时一个稍庞杂的调用和同步相关会致使代码充溢了庞杂的同步搜检和层层回调,难以了解和珍爱。这个结果从素质上媾和下面HTML的例子一样,是因为大都通用措辞并未把异步作为基础元素/语义,很多异步完成情势是向措辞的让步。针对这个结果,我用Javascript编写了一个基于流通接口的异步DSL,示例代码以下:



  1. //Javascript

  2. $.begin()

  3. .async(newTask('task1'), 'task1')

  4. .async(newTask('task2'), 'task2')

  5. .async(newTask('task3'), 'task3')

  6. .when()

  7. .each_done(function(name, result) {

  8. console.log(name + ': ' + result);})

  9. .all_done(function(){ console.log('good, all completed'); })

  10. .timeout(function(){

  11. console.log('timeout!!');

  12. $.begin()

  13. .async(newTask('task4'), 'task4')

  14. .when()

  15. .each_done(function(name, result) {

  16. console.log(name + ': ' + result); })

  17. .end();}

  18. , 3000)

  19. .end();


下面的代码只是一句Javascript调用,但从另外一个角度看它却像一段描写异步调用的DSL法式。它经由过程流通接口定义了begin when end的语法结构,begin背面跟的是启动异步调用的代码;when背面是异步结果处理惩罚,可以遴选each_done, all_done, timeout中的一种或多种。而begin when end结构自己是可以嵌套的,比如下面的代码在timeout处理惩罚分支中就包括了另外一个begin when end结构。经由过程这个DSL,我们可以比基于回调的体式款式更好地表达异步调用的同步和嵌套相关。


下面先容了用流通接口结构的4种典范笼统,出此之外另有很多其他的笼统和运用场所,比如:很多单元测试框架就经由过程流通接口定义了单元测试的DSL。虽然下面的例子以Javascript等静态措辞占多数,但其实流通接口所凭仗的语法根本其实不刻薄,即使在Java多么的静态措辞中,一样可以轻松地运用。流通接口差别于传统的API假想,了解和运用流通接口关键是要打破措辞笼统机制带来的定势思想,根据结果域拔取得当的笼统维度,运用措辞的基础语法结构范畴特定的语义和语法。


免责声明:本文内容由互联网用户自发贡献自行上传,本网站也不承担相关的法律责任。如果您发现本文章中有涉嫌抄袭的内容,请发送邮件至:sales@sznetsoft.com或者至电给本网站进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权的内容。
下一条:
无下一条记录
相关信息
  • QQ好友
  • QQ空间
  • 腾讯微博
  • 新浪微博
  • 人人网
  • 豆瓣网
  • Facebook
  • Twitter
  • linkedin
  • 谷歌Buzz


线

网软通在线


在线客服: 点击这里给我发消息                        

1231.jpg

留言内容