函数式编程-Supplier 在实际环境的使用

业务场景适配
业务场景 -> 接口缓存

在这样一个典型的缓存场景中,业务的样板代码会很繁琐,而且一旦业务中大量使用缓存的话,样板代码会占据很大的篇幅。

// 伪代码
value = redis.get(key)
if (null == value) {
    data = mybatis.get(param)
    redis.set(key, data)
    return data
}
return value;

代码
这是一个在构造函数种传入了 supplier 的辅助类。redis 操作涉及到的 过期时间/时间单位 也封装到同一个构造函数。包含一个定义好的方法 get,其内容就是调用传入的 supplier 的 get 方法。

public class RedisSupplier <T> {

    private int expire;

    private TimeUnit timeUnit;

    Supplier<T> supplier;

    public int getExpire() {
        return expire;
    }

    public void setExpire(int expire) {
        this.expire = expire;
    }

    public TimeUnit getTimeUnit() {
        return timeUnit;
    }

    public void setTimeUnit(TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
    }

    public Supplier<T> getSupplier() {
        return supplier;
    }

    public void setSupplier(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    public RedisSupplier(int expire, TimeUnit timeUnit, Supplier<T> supplier) {
        this.expire = expire;
        this.timeUnit = timeUnit;
        this.supplier = supplier;
    }

    public T get() {
        return this.supplier.get();
    }

}

用于模拟缓存使用场景的 cacheUtil 类,注意这个 get 方法,其中传入了前面定义好的 redisSupplier 类实例。get 方法调用的源头就是 supplier.get,之所以在 jdk 标准的函数上封装了一层,是因为我们需要更多的自定义参数(缓存时长设置)。

public class CacheUtil {

    private static HashMap<String, Object> localCache = new HashMap<>();

    public <T> T get(String key, RedisSupplier<T> redisSupplier) {
        Object value = localCache.get(key);
        if (Objects.isNull(value)) {
            T result = redisSupplier.get();
            this.set(key, result, redisSupplier.getExpire(), redisSupplier.getTimeUnit());
            return result;
        }
        return (T) value;
    }

    public void set(String key, Object value, int expire, TimeUnit timeUnit) {
        localCache.put(key, value);
    }
}

前面着重强调的样板代码,基本上都被封装在了这个 cacheUtil 类的 get 方法中。省略了这部分的代码,我们业务代码的编写就会很便捷。
如下为使用示例:

    public static void main(String[] args) {
        RedisSupplier<String> redisSupplier = new RedisSupplier<>(1, TimeUnit.DAYS, () -> "valueB");
        CacheUtil cacheUtil = new CacheUtil();
        String result = cacheUtil.get("B", redisSupplier);
        System.out.println(result);

    }

supplier 函数定义了当缓存中没获取到 key-B 的值的时候,用于给这个 key-B 设置值的方法,我们直接设置为了 valueB。实际使用场景就可以替换为 mybatis 的数据持久层获取数据的操作。

public class ServiceSupplier {

    public void invoke(Supplier<UserInfo> supplier){
        UserInfo userInfo = supplier.get();
        System.out.println(userInfo);
    }
}


public class ServiceSupplierTest { public static void main(String[] args) { ServiceSupplier serviceSupplier = new ServiceSupplier(); UserInfo userInfo = new UserInfo(); userInfo.setUserName("guodong"); userInfo.setCreateDay("2099-00-99"); userInfo.setPhone("17899889900"); userInfo.setPassWord("123454321"); Supplier<UserInfo> supplier = () -> userInfo; serviceSupplier.invoke(supplier); } }

写法二总结:

package com.example.springstudy.test.supplier;

import cn.hutool.core.lang.UUID;

import java.util.function.Supplier;

/**
 * @Author: GuoDong
 * @Description:
 * @Date 2023-02-06 16:34:05
 * @Version 1.0
 **/
public class TestSupplier {

    /**
     * 处理逻辑
     * @param name
     */
    public void invoke(Supplier<String> name){
        System.out.println(name.get());
    }


    /**
     * 调用方
     * @param args
     */
    public static void main(String[] args) {
        TestSupplier testSupplier = new TestSupplier();
        AA aa = new AA();
        Supplier<String> supplier = aa::getName;
        testSupplier.invoke(supplier);
    }
    
}



class AA{
    
    /**
     * 提供入参
     * @return
     */
    public String getName(){
        return UUID.randomUUID().toString();
    }

}

总结:supplier 相当于其实就是提供了一个入参,并且约束了入参类型。然后在实现里面处理传入的参数。调用写法有两种方式:第一种是:() -> 入参实体对象;第二种是:实体类bean :: 方法函数;第二种调用方式其实就是bean.方法();

 

posted @ 2023-02-06 10:51  郭慕荣  阅读(103)  评论(0编辑  收藏  举报