Java链式编程调用解析 - 知乎

Java链式编程调用解析

何为链式编程?

StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("123").append("234").append("231232");

1.Builder模式的使用场景

  • 相同的方法,不同的执行顺序,产生不同的时间结果
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不同时
  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候用建造者模式非常适合
  • 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值

经典版本链式调用示例

/**
 * @author caishen
 * @version 1.0
 * @className NutritionFacts
 * @date 2019/12/17 9:48
 * 自分で書いたコードの各行を担当する
 * Java 链式调用
 **/
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public int getServingSize() {
        return servingSize;
    }

    public int getServings() {
        return servings;
    }

    public int getCalories() {
        return calories;
    }

    public int getFat() {
        return fat;
    }

    public int getSodium() {
        return sodium;
    }

    public int getCarbohydrate() {
        return carbohydrate;
    }

    public static class Builder {
        // 必要 入参
        private final int servingSize;
        private final int servings;

        // 可选参数 默认值为0
        private int calories      = 0;
        private int fat           = 0;
        private int sodium        = 0;
        private int carbohydrate  = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val) {
            this.calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts nutritionFacts = new Builder(1, 2).calories(10).build();
        System.out.println(nutritionFacts.getCalories());
    }
}

重点强调

  • NutritionFacts类的构造方法是私有的。也就是说调用者不能直接创建NutritionFacts对象。
  • NutritionFacts类的属性都是不可变的。所有的属性都添加了final修饰符,并且在构造方法中设置了值。并且,对外只提供getters方法。
  • Builder的内部类构造方法中只接收必传的参数,并且该必传的参数使用了final修饰符。

2.Java8 Builder 链式调用示例

public class GenericBuilder<T> {

    private final Supplier<T> instantiator;
    private List<Consumer<T>> instantiatorModifiers = new ArrayList<>();
    private List<Consumer<T>> keyValueModifiers = new ArrayList<>();

    public GenericBuilder(Supplier<T> instantiator) {
        this.instantiator = instantiator;
    }

    public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
        return new GenericBuilder<T>(instantiator);
    }

    public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
        Consumer<T> c = instance -> consumer.accept(instance, value);
        instantiatorModifiers.add(c);
        return this;
    }

    public <K, V> GenericBuilder<T> with(KeyValueConsumer<T, K, V> consumer, K key, V value) {
        Consumer<T> c = instance -> consumer.accept(instance, key, value);
        keyValueModifiers.add(c);
        return this;
    }

    public T build() {
        T value = instantiator.get();
        instantiatorModifiers.forEach(modifier -> modifier.accept(value));
        keyValueModifiers.forEach(keyValueModifier -> keyValueModifier.accept(value));
        instantiatorModifiers.clear();
        keyValueModifiers.clear();
        return value;
    }

    @FunctionalInterface
    interface KeyValueConsumer<T, K, V> {
        void accept(T t, K k, V v);

        default KeyValueConsumer<T, K, V> andThen(KeyValueConsumer<? super T, ? super K, ? super V> after) {
            Objects.requireNonNull(after);

            return (t, k, v) -> {
                accept(t, k, v);
                after.accept(t, k, v);
            };
        }
    }
}

调用方式

/**
 * @author caishen
 * @version 1.0
 * @className Order
 * @date 2019/12/17 11:15
 * 自分で書いたコードの各行を担当する
 **/
public class Order {

    private String code;

    private List<String> offers;

    private Map<String, Object> features;

    public void addOffer(String offer) {
        offers = Optional.ofNullable(offers).orElseGet(ArrayList::new);
        offers.add(offer);
    }

    public <T> void addFeature(String key, T value) {
        features = Optional.ofNullable(features).orElseGet(HashMap::new);
        features.put(key, value);
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public List<String> getOffers() {
        return offers;
    }

    public void setOffers(List<String> offers) {
        this.offers = offers;
    }

    public Map<String, Object> getFeatures() {
        return features;
    }

    public void setFeatures(Map<String, Object> features) {
        this.features = features;
    }

    @Override
    public String toString() {
        return "Order{" +
                "code='" + code + '\'' +
                ", offers=" + offers +
                ", features=" + features +
                '}';
    }

    public static void main(String[] args) {
        Order order = GenericBuilder.of(Order::new).with(Order::setCode, "123").with(Order::addOffer, "满100减50")
                .with(Order::addFeature, "category", "shoe").with(Order::addFeature, "color", "red").build();

        System.out.println(order);
    }
}

3.Lombok @Builder @Singular 注解 链式调用示例

/**
 * @author caishen
 * @version 1.0
 * @className User
 * @date 2019/12/17 11:37
 * 自分で書いたコードの各行を担当する
 * @Singular注解 必须在@Builder类 里面才生效
 **/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class User {
    /**
     * id  @Builder.Default 指定默认值
     */
    @Builder.Default
    private int id;
    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String password;
    /**
     * 年龄
     */
    private int age;
    /**
     * 集合 value属性指定调用名称
     */
    @Singular(value = "add")
    private List<String> keys;
    /**
     * 集合 value属性指定调用名称
     */
    @Singular(value = "put")
    private Map<String,String> maps;

    public static void main(String[] args) {
        User user = User.builder()
                .age(12)
                .id(1)
                .userName("zhangsan")
                .password("123")
                .add("333")
                .add("999")
                .add("123")
                .put("123","234")
                .build();
        System.out.println(user);
    }
}

反编译之后的代码

public class User {
    private int id;
    private String userName;
    private String password;
    private int age;
    private List<String> keys;
    private Map<String, String> maps;

    public static void main(String[] args) {
        User user = builder().age(12).userName("zhangsan").password("123").add("333").add("999").add("123").put("123", "234").build();
        System.out.println(user);
    }

    public static User.UserBuilder builder() {
        return new User.UserBuilder();
    }

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

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setKeys(List<String> keys) {
        this.keys = keys;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public int getId() {
        return this.id;
    }

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

    public String getPassword() {
        return this.password;
    }

    public int getAge() {
        return this.age;
    }

    public List<String> getKeys() {
        return this.keys;
    }

    public Map<String, String> getMaps() {
        return this.maps;
    }

    public User() {
    }

    @ConstructorProperties({"id", "userName", "password", "age", "keys", "maps"})
    public User(int id, String userName, String password, int age, List<String> keys, Map<String, String> maps) {
        this.id = id;
        this.userName = userName;
        this.password = password;
        this.age = age;
        this.keys = keys;
        this.maps = maps;
    }

    public String toString() {
        return "User(id=" + this.getId() + ", userName=" + this.getUserName() + ", password=" + this.getPassword() + ", age=" + this.getAge() + ", keys=" + this.getKeys() + ", maps=" + this.getMaps() + ")";
    }

    public static class UserBuilder {
        private int id;
        private String userName;
        private String password;
        private int age;
        private ArrayList<String> keys;
        private ArrayList<String> maps$key;
        private ArrayList<String> maps$value;

        UserBuilder() {
        }

        public User.UserBuilder id(int id) {
            this.id = id;
            return this;
        }

        public User.UserBuilder userName(String userName) {
            this.userName = userName;
            return this;
        }

        public User.UserBuilder password(String password) {
            this.password = password;
            return this;
        }

        public User.UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        public User.UserBuilder add(String add) {
            if (this.keys == null) {
                this.keys = new ArrayList();
            }

            this.keys.add(add);
            return this;
        }

        public User.UserBuilder keys(Collection<? extends String> keys) {
            if (this.keys == null) {
                this.keys = new ArrayList();
            }

            this.keys.addAll(keys);
            return this;
        }

        public User.UserBuilder clearKeys() {
            if (this.keys != null) {
                this.keys.clear();
            }

            return this;
        }

        public User.UserBuilder put(String putKey, String putValue) {
            if (this.maps$key == null) {
                this.maps$key = new ArrayList();
                this.maps$value = new ArrayList();
            }

            this.maps$key.add(putKey);
            this.maps$value.add(putValue);
            return this;
        }

        public User.UserBuilder maps(Map<? extends String, ? extends String> maps) {
            if (this.maps$key == null) {
                this.maps$key = new ArrayList();
                this.maps$value = new ArrayList();
            }

            Iterator var2 = maps.entrySet().iterator();

            while(var2.hasNext()) {
                Entry<? extends String, ? extends String> $lombokEntry = (Entry)var2.next();
                this.maps$key.add($lombokEntry.getKey());
                this.maps$value.add($lombokEntry.getValue());
            }

            return this;
        }

        public User.UserBuilder clearMaps() {
            if (this.maps$key != null) {
                this.maps$key.clear();
                this.maps$value.clear();
            }

            return this;
        }

        public User build() {
            List keys;
            switch(this.keys == null ? 0 : this.keys.size()) {
            case 0:
                keys = Collections.emptyList();
                break;
            case 1:
                keys = Collections.singletonList(this.keys.get(0));
                break;
            default:
                keys = Collections.unmodifiableList(new ArrayList(this.keys));
            }

            Map maps;
            switch(this.maps$key == null ? 0 : this.maps$key.size()) {
            case 0:
                maps = Collections.emptyMap();
                break;
            case 1:
                maps = Collections.singletonMap(this.maps$key.get(0), this.maps$value.get(0));
                break;
            default:
                Map<String, String> maps = new LinkedHashMap(this.maps$key.size() < 1073741824 ? 1 + this.maps$key.size() + (this.maps$key.size() - 3) / 3 : 2147483647);

                for(int $i = 0; $i < this.maps$key.size(); ++$i) {
                    maps.put(this.maps$key.get($i), (String)this.maps$value.get($i));
                }

                maps = Collections.unmodifiableMap(maps);
            }

            return new User(this.id, this.userName, this.password, this.age, keys, maps);
        }

        public String toString() {
            return "User.UserBuilder(id=" + this.id + ", userName=" + this.userName + ", password=" + this.password + ", age=" + this.age + ", keys=" + this.keys + ", maps$key=" + this.maps$key + ", maps$value=" + this.maps$value + ")";
        }
    }
}

4.框架中用到的链式调用 Quartz/Shiro/Mybatis/Spring-security

4.1 JobBuilder创建一个JobDetail

JobDetail jobDetail = JobBuilder.newJob()
            .withIdentity("demo")
            .storeDurably(true)
            .build();

4.2 TriggerBuilder创建一个Trigger 触发器

Trigger trigger = TriggerBuilder.newTrigger()
      .withSchedule(SimpleScheduleBuilder.simpleSchedule()
          .withIntervalInSeconds(interval).repeatForever())
      .startNow()
      .build();

4.3 Spring-security创建一个安全用户

User user2 = (User) User.withUsername("zhangsan").password("123").authorities("admin")
                .accountExpired(true)
                .disabled(false)
                .accountLocked(false)
                .credentialsExpired(true)
                .build();

5.多种链式调用实现比较

    • *

参考:


原网址: 访问
创建于: 2023-06-12 09:12:50
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论