链式编程学习

什么是链式编程

在我们编写代码过程中听到过很多说法;像面向切面编程、函数式编程、面向对象编程、泛式编程、面向接口等。

所谓的链式编程,则是类似与StringBuffer的append方法的写法:

StringBuffer bf = new StringBuffer();
bf.append("x").append("xx").append("xx");

或者在使用jQuery时肯定对它的链式编程惊艳到,慢慢的其它语言这种编程模式也逐渐增多。其本身并不复杂,在调用方法时,方法最后返回对象本身,以达到链式编程的效果。

  • 普通写法:
  1. 维护性强
  2. 对方法的返回类型无要求
  3. 对程序员的业务要求适中
  • 链式写法:
  1. 编程性强
  2. 可读性强
  3. 代码简洁
  4. 对程序员的业务能力要求高
  5. 不太利于代码调试

Java链式写法,子类继承父类的属性,也可以返回子类的对象,只是需要重写基类的Set方法;只要****return this即可具有相应的编程模式,但是需要根据业务需求使用不同的方法方式进行实现。

如何实现一个简单的链式编程

public class User {
    private String userCode;
    private String userName;
    private String userPassword;
    public String getUserCode() {
        return userCode;
    }
    public User setUserCode(String userCode) {
        this.userCode = userCode;
        return this;
    }
    public String getUserName() {
        return userName;
    }
    public User setUserName(String userName) {
        this.userName = userName;
        return this;
    }
    public String getUserPassword() {
        return userPassword;
    }
    public User setUserPassword(String userPassword) {
        this.userPassword = userPassword;
        return this;
    }
}

创建实体类的时候可以这样写:

@Test
    public void UserTest01(){
        User user = new User().setUserCode("UUID").setUserName("xx").setUserPassword("DES加密算法");
    }

静态初始化方法 of

Spring中有很多方法提供了静态of方法,可以更方便的创建对象,结合return this将更为实用的实现链式编程,算是一种比较不错得扩展措施。

public class User {

    private String userCode;

    private String userName;

    private String userPassword;

    private User(String userCode, String userName) {
        this.userCode = userCode;
        this.userName = userName;
    }

    private User(String userCode, String userName, String userPassword) {
        this(userCode, userName);
        this.userPassword = userPassword;
    }

    // PageRequest时使用
    public static User of(String userCode, String userName) {
        return of(userCode, userName, null);
    }

    // 返回结果时,具有命中用户信息的使用
    public static User of(String userCode, String userName, String userPassword) {
        return new User(userCode, userName, userPassword);
    }

    public String getUserCode() {
        return this.userCode;
    }

    public String getUserName() {
        return this.userName;
    }

    public String getUserPassword() {
        return this.userPassword;
    }
}

具体操作可以根据你的需求去设计,上面栗子实现了三个成员变量用户账号、昵称、密码,并且未实现成员变量的Set方法;构造方法全部为私有,实现了静态的of方法来创建用户对象。

Builder模式链式编程(Builder模式也称为建造者模式)

不知道在开发过程是否遇到过特别特别长的类构造器,例如:

User user=new User(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,....)

Builder 模式的优点:

  • 链式调用,优雅、清晰、一目了然
  • 一行代码完成对象创建,避免了多行代码赋值过程出错
  • 省去了大量冗余变量,避免变量复制出错

Builder 模式的缺点:

  • 需要冗余的 Builder 类,以及大量相等重复的成员变量,大大增加了代码量,维护难度相对较大
  • 只适合一次赋值创建对象,多次赋值的场景还需要新增 set 方法配合,不是很灵活

Builder模式也是目前较为常用的一种链式编程方法,Spring中有适量的依据此模式进行的编码。以常见的ResponseEntity类来看,其内部定义了Builder接口,并默认实现了一个DefaultBuild内部类,内部方法采用return this实现链式模式,同时在ResponseEntity中提供了类似的Builder方法,如ok、status等静态方法。

从这些类的实现原理看,实现Builder模式也比较简单,一方面创建一个内部Builder类,实现相应信息的创建;同时在目标类中,实现一个静态的builder方法,用于创建Builder对象,并启动链式模式;最后再由内部类提供一个终止方法,该终止方法将完成目标类的创建。

public class User {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private User(PersonBuilder builder) {
        this.id = builder.id;
        this.name = builder.name;
    }

    public static PersonBuilder builder() {
        return new PersonBuilder();
    }

    public static class PersonBuilder implements Builder<User> {
        private String id;
        private String name;

        public PersonBuilder id(String id) {
            this.id = id;
            return this;
        }

        public PersonBuilder name(String name) {
            this.name = name;
            return this;
        }

        @Override
        public User build() {
            return new User(this);
        }
    }
}

测试一下下:

@Test
    void contextLoads() {
        User user = User.builder().id("1").name("xx").build();
        System.out.println(Optional.ofNullable(user).map(User::getId).orElse("12"));
        System.out.println(Optional.ofNullable(user).map(User::getName).orElse("xx"));
    }

Lombok 链式编程

引入依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

@Accessors(chain = true)

@Accessors Accessor的中文含义是存取器,@Accessors用于配置getter和setter方法的生成结果,有三个属性

  1. fluent
    fluent的中文含义是流畅的,设置为true,则getter和setter方法的方法名都是基础属性名,且setter方法返回当前对象
    栗子:
@Data
@Accessors(fluent = true)
public class User {
    private Long userId;
    private String userName;
    //方法体略
    public Long userId() {}
    public User userId(Long userId) {}
    public String userName() {}
    public User userName(String userName) {}
}
  1. chain
    chain的中文含义是链式的,设置为true,则setter方法返回当前对象
    栗子:
@Data
@Accessors(chain = true)
public class User {
    private Long userId;
    private String userName;
    //方法体略
    public User setUserId(Long userId) {}
    public User setUserName(String userName) {}
}
  1. prefix
    prefix的中文含义是前缀,用于生成getter和setter方法的字段名会忽视指定前缀(遵守驼峰命名)
    栗子:
@Data
@Accessors(prefix = "p")
class User {
private Long pUserId;
private String pUserName;
//方法体略
public Long getUserId() {}
public void setUserId(Long UserId) {}
public String getUserName() {}
public void setUserName(String UserName) {}
}

Lombok 静态的链式编程

静态的链式编程 比 普通的链式编程 的好处:

  • 创建对象更简洁
  • 可以在静态方法、静态代码块等中使用
  • 对于必输字段,可以强制要求
@Accessors(chain = true)
@Data
@RequiredArgsConstructor(staticName = "of")
public class Student {
	@NonNull
	private String userName;
	private int age;
}

@RequiredArgsConstructor

会生成一个包含常量,和标识了@NotNull的变量 的构造方法。生成的构造方法是private,如何想要对外提供使用可以使用staticName选项生成一个static方法。

Lombok 实现 builder模式的链式bean

只需一个注解 @Builder

@Builder
@Data
public class StudentBean {
	private String userName;
	private int age;
}