Fluent Interface(流畅接口)是一种编程模式,旨在创建易于阅读和使用的代码。它通过使用方法链(method chaining)来实现连续的调用。
在使用流畅接口时,每个方法调用都返回当前对象的引用,以实现链式调用。这样的设计使得代码更加清晰和可读,提供了一种自然的、连贯的交互方式。
以下是一个使用流畅接口的示例,假设存在一个名为Person的类:
public class Person {
private String name;
private Integer age;
public Person setName(String name) {
this.name = name;
return this;
}
public Person setAge(Integer age) {
this.age = age;
return this;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
使用流畅接口,可以这样调用:
Person person = new Person()
.setName("John")
.setAge(25);
在上述示例中,setName()和setAge()方法都返回Person对象的引用,因此可以通过链式调用来设置属性值。
那如何让 setName 只能在 setAge 之后调用呢?
要实现在调用setName()之前必须先调用setAge()的限制,可以使用一种叫做"Builder模式"的设计模式来实现。
我们对 Person 类进行改造:
public class Person {
private String name;
private Integer age;
private Person() {
}
public static Builder newBuilder() {
return new Builder();
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public static class Builder {
private Person person;
private Builder() {
person = new Person();
}
public Builder setAge(Integer age) {
person.age = age;
return this;
}
public Builder setName(String name) {
if (person.age != null) {
person.name = name;
} else {
throw new IllegalStateException("Please set age before setting the name.");
}
return this;
}
public Person build() {
return person;
}
}
}
使用Builder模式,现在可以这样调用:
Person person = Person.newBuilder()
.setAge(25)
.setName("John")
.build();
在这个示例中,只有在先调用setAge()方法之后,才能调用setName()方法。如果尝试在没有调用setAge()的情况下调用setName(),会抛出IllegalStateException异常。
Builder模式的好处是可以提供更多的约束和校验逻辑,确保对象的正确创建。同时,它也提供了一种流畅的接口,使代码更易读和易用。
抛出异常不优雅,能否强制指定调用的顺序?
我们可以通过利用接口来实现这个需求,以下是优化后的代码:
public interface Step1 {
Step2 setAge(Integer age);
}
public interface Step2 {
Person.Builder setName(String name);
}
public class Person {
private String name;
private Integer age;
private Person() {
}
public static Step1 newBuilder() {
return new Builder();
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public static class Builder implements Step1, Step2 {
private final Person person;
private Builder() {
person = new Person();
}
public Step2 setAge(Integer age) {
person.age = age;
return this;
}
public Builder setName(String name) {
person.name = name;
return this;
}
public Person build() {
return person;
}
}
public static void main(String[] args) {
Person person = Person.newBuilder().setAge(25).setName("Tom").build();
// 格式化输出
System.out.printf("age: %d, name: %s", person.getAge(), person.getName());
}
}
优化后我们可以看到,在代码提示里只会出现指定的方法,满足了按顺序调用的需求。