Fluent Interface 是什么?如何保证语义正确性和连贯性?

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());
    }
}

优化后我们可以看到,在代码提示里只会出现指定的方法,满足了按顺序调用的需求。
在这里插入图片描述

扫描二维码关注公众号,回复: 15646474 查看本文章

猜你喜欢

转载自blog.csdn.net/ChinaLiaoTian/article/details/131393120