函数式编程-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.方法();
郭慕荣博客园