设计流畅的API(Fluent API)

banq 16-08-23
         

流畅接口是由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