流畅接口是由Martin Fowler和Eric Evans创造的,流畅API意味着你构建一个API需要遵循以下要点:
1.API用户能够容易理解API
2.API为完成一个任务能够执行一系列动作,比如Java中可以看成是一系列方法调用,方法链。
3.每个方法名称应该是与业务领域相关的专门术语
4.API应该能提示指导API用户下一步用什么,以及某个时刻用户可能采取的操作。
假设你要设计一个业务域的API,比如是零售行业,那么应该有一些零售领域存在的共同的术语 ,在一定情境(任务)或上下文下,应该会采取一系列行动来完成这项任务或上下文情境。比如说,一张发票的生成必须遵循一定的步骤。
现在,当你设计一个API接口时,设计方式是:当用户调用计费服务用于发票生成时,用户可以流利地执行每一步,以完成发票的生成,API会帮助用户对计费服务调用步骤的执行。
当一个API方法被用户调用时,该方法将执行其任务并返回一个对象,这将有助于指导用户下一步该做什么-直到所有步骤执行。不同于一个标准API,它是使用一个连续的方式调用API的方法,以便成功完成一个任务。因此,API用户必须非常了解服务的步骤(服务的方法)。
案例:假设我们为一个餐馆设计一个API,作为餐馆客户,他会执行以下动作步骤:
1.用户进入餐馆
2.查询价目选择菜单
3.订餐
4.吃饭
5.付费。
在标准的API(非流畅API)设计中,会如下做法:
1.创建一个“餐厅”界面。
2.创建一个餐厅实现类。组成菜单类menucard。
3.创造餐厅属性名称,包括getter和setter等方法。
4.在menucard类中,有条目列表。暴露的一些方法,如showmenu(), ordermenu(),等。
5.每个条目都有名称和成本等特性以及相应的getter和setter。
6.当用户调用这个API的API,他/她会调用一个方法序列(进入餐厅,调用showmenu(),然后调用ordermenu(),等)。完成上述客户步骤。
上面这张设计不是流畅的,完成一项任务需要很多顺序语句执行,API用户必须了解这些顺序。
看看流畅API设计:
1.创建一个接口iresturant,有两种方法A.
2.打印餐厅名字,注意 返回类型 返回自身,因为在显示名称以后,用户希望看到的菜单。
3. show()方法返回menucard。
(这里暗示有两种方法:一是名字和另一个show(下一个操作用户要执行的)
4. IMENU有4个重要的方法showmenu():order(),eat(),pay(),所有方法返回menuhandler实现,所以我们可以执行这些动作中的一个。这是再次暗示。
Java代码:
package com.example.fluentapi.contract; public interface IResturant { public IResturant name(String name); public IMenu show(); } package com.example.fluentapi.contract; public interface IMenu{ public IMenu order(int index); public IMenu eat(); public IMenu pay(); public IItem get(int index); } package com.example.fluentapi.contract; public interface IItem { public IItem name(); public Integer cost(); }
|
实现:
package com.example.fluentapi.impl; import com.example.fluentapi.contract.IMenu; import com.example.fluentapi.contract.IResturant; public class Arsalan implements IResturant{ String name; String IMenu; public IResturant name(String name) { this.name=name; System.out.println("Enter to hotel :: " + name); return this; } public IMenu show() { // TODO Auto-generated method stub ArsalanMenuHandler handler = new ArsalanMenuHandler(); handler.showMenu(); return handler; } } package com.example.fluentapi.impl; import java.util.ArrayList; import java.util.List; import com.example.fluentapi.contract.IItem; import com.example.fluentapi.contract.IMenu; public class ArsalanMenuHandler implements IMenu{ List<IItem> menuList = new ArrayList<IItem>(); List<IItem> selectedList = new ArrayList<IItem>(); public ArsalanMenuHandler() { IItem biriyani = new IItem(){ public IItem name() { System.out.println("Mutton Biriyani"); return this; } public Integer cost() { return 180; } }; IItem muttonChap = new IItem(){ public IItem name() { System.out.println("Mutton Chap"); return this; } public Integer cost() { return 160; } }; IItem firni = new IItem(){ public IItem name() { System.out.println("Firni"); return this; } public Integer cost() { return 100; } }; menuList.add(biriyani); menuList.add(muttonChap); menuList.add(firni); } public IMenu order(int index) { // TODO Auto-generated method stub IItem item (index); selectedList.add(item); System.out.println("Order given ::"); item.name(); return this; } public IMenu eat() { for(IItem item : selectedList) { System.out.println("eating "); item.name(); } return this; } public IMenu pay() { int cost=0; for(IItem item : selectedList) { cost = cost + item.cost(); } System.out.println("Paying Rupees" + cost); return this; } @Override public IItem get(int index) { // TODO Auto-generated method stub if(index <3) { return menuList.get(index); } return null; } public void showMenu(){ System.out.println("MENU IN ARSALAN"); for(IItem item : menuList) { item.name(); } } }
|
测试:
package com.example.fluentapi.impl; public class FluentApiTest { publicstaticvoid main(String[] args) { new Arsalan().name("ARSALAN").show().order(0).order(1).eat().pay(); } }
|
输出:
Enter to hotel :: ARSALAN MENU IN ARSALAN Mutton Biriyani Mutton Chap Firni Order given :: Mutton Biriyani Order given :: Mutton Chap eating Mutton Biriyani eating Mutton Chap Paying Ruppes340
|
我们是通过下面方法链实现流畅调用的:
new Arsalan().name("ARSALAN").show().order(0).order(1).eat().pay();
原文:
Design a Fluent API in Java - DZone Integration