接上篇:https://developer.aliyun.com/article/1227318?spm=a2c6h.13148508.setting.20.48e04f0eaBVGWH
十、 利用设计模式
1. 模板方法模式
模板方法模式(Template Method Pattern)定义一个固定的算法框架,而将算法的一些步骤放到子类中实现,使得子类可以在不改变算法框架的情况下重定义该算法的某些步骤。
普通
@Repository public class UserValue { /** 值操作 */ @Resource(name = "stringRedisTemplate") private ValueOperations<String, String> valueOperations; /** 值模式 */ private static final String KEY_FORMAT = "Value:User:%s";
/** 设置值 */ public void set(Long id, UserDO value) { String key = String.format(KEY_FORMAT, id); valueOperations.set(key, JSON.toJSONString(value)); }
/** 获取值 */ public UserDO get(Long id) { String key = String.format(KEY_FORMAT, id); String value = valueOperations.get(key); return JSON.parseObject(value, UserDO.class); }
... }
@Repository public class RoleValue { /** 值操作 */ @Resource(name = "stringRedisTemplate") private ValueOperations<String, String> valueOperations; /** 值模式 */ private static final String KEY_FORMAT = "Value:Role:%s";
/** 设置值 */ public void set(Long id, RoleDO value) { String key = String.format(KEY_FORMAT, id); valueOperations.set(key, JSON.toJSONString(value)); }
/** 获取值 */ public RoleDO get(Long id) { String key = String.format(KEY_FORMAT, id); String value = valueOperations.get(key); return JSON.parseObject(value, RoleDO.class); }
... } |
精简:
public abstract class AbstractDynamicValue<I, V> { /** 值操作 */ @Resource(name = "stringRedisTemplate") private ValueOperations<String, String> valueOperations;
/** 设置值 */ public void set(I id, V value) { valueOperations.set(getKey(id), JSON.toJSONString(value)); }
/** 获取值 */ public V get(I id) { return JSON.parseObject(valueOperations.get(getKey(id)), getValueClass()); }
...
/** 获取主键 */ protected abstract String getKey(I id);
/** 获取值类 */ protected abstract Class<V> getValueClass(); }
@Repository public class UserValue extends AbstractValue<Long, UserDO> { /** 获取主键 */ @Override protected String getKey(Long id) { return String.format("Value:User:%s", id); }
/** 获取值类 */ @Override protected Class<UserDO> getValueClass() { return UserDO.class; } }
@Repository public class RoleValue extends AbstractValue<Long, RoleDO> { /** 获取主键 */ @Override protected String getKey(Long id) { return String.format("Value:Role:%s", id); }
/** 获取值类 */ @Override protected Class<RoleDO> getValueClass() { return RoleDO.class; } } |
2. 访问者模式
访问者模式(Visitor),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
普通:
public interface DataHandler<T> { /** 解析数据 */ public T parseData(Record record);
/** 存储数据 */ public boolean storeData(List<T> dataList); }
public <T> long executeFetch(String tableName, int batchSize, DataHandler<T> dataHandler) throws Exception { // 构建下载会话 DownloadSession session = buildSession(tableName);
// 获取数据数量 long recordCount = session.getRecordCount(); if (recordCount == 0) { return 0; }
// 进行数据读取 long fetchCount = 0L; try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) { // 依次读取数据 Record record; List<T> dataList = new ArrayList<>(batchSize); while ((record = reader.read()) != null) { // 解析添加数据 T data = dataHandler.parseData(record); if (Objects.nonNull(data)) { dataList.add(data); }
// 批量存储数据 if (dataList.size() == batchSize) { boolean isContinue = dataHandler.storeData(dataList); fetchCount += batchSize; dataList.clear(); if (!isContinue) { break; } } }
// 存储剩余数据 if (CollectionUtils.isNotEmpty(dataList)) { dataHandler.storeData(dataList); fetchCount += dataList.size(); dataList.clear(); } }
// 返回获取数量 return fetchCount; }
/** 使用案例 */ long fetchCount = odpsService.executeFetch("user", 5000, new DataHandler() { /** 解析数据 */ @Override public T parseData(Record record) { UserDO user = new UserDO(); user.setId(record.getBigint("id")); user.setName(record.getString("name")); return user; }
/** 存储数据 */ @Override public boolean storeData(List<T> dataList) { userDAO.batchInsert(dataList); return true; } }); |
精简:
public <T> long executeFetch(String tableName, int batchSize, Function<Record, T> dataParser, Function<List<T>, Boolean> dataStorage) throws Exception { // 构建下载会话 DownloadSession session = buildSession(tableName);
// 获取数据数量 long recordCount = session.getRecordCount(); if (recordCount == 0) { return 0; }
// 进行数据读取 long fetchCount = 0L; try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) { // 依次读取数据 Record record; List<T> dataList = new ArrayList<>(batchSize); while ((record = reader.read()) != null) { // 解析添加数据 T data = dataParser.apply(record); if (Objects.nonNull(data)) { dataList.add(data); }
// 批量存储数据 if (dataList.size() == batchSize) { Boolean isContinue = dataStorage.apply(dataList); fetchCount += batchSize; dataList.clear(); if (!Boolean.TRUE.equals(isContinue)) { break; } } }
// 存储剩余数据 if (CollectionUtils.isNotEmpty(dataList)) { dataStorage.apply(dataList); fetchCount += dataList.size(); dataList.clear(); } }
// 返回获取数量 return fetchCount; }
/** 使用案例 */ long fetchCount = odpsService.executeFetch("user", 5000, record -> { UserDO user = new UserDO(); user.setId(record.getBigint("id")); user.setName(record.getString("name")); return user; }, dataList -> { userDAO.batchInsert(dataList); return true; }); ``` |
普通的访问者模式,实现时需要定义DataHandler接口,调用时需要实现DataHandler匿名内部类,代码较多较繁琐。而精简后的访问者模式,充分利用了函数式编程,实现时无需定义接口,直接使用Function接口;调用时无需实现匿名内部类,直接采用lambda表达式,代码较少较简洁。
3. 代理模式
Spring中最重要的代理模式就是AOP(Aspect-Oriented Programming,面向切面的编程),是使用JDK动态代理和CGLIB动态代理技术来实现的。
普通:
精简1:
基于@ControllerAdvice的异常处理:
精简2:
基于AOP的异常处理:
接下篇:https://developer.aliyun.com/article/1227315?groupCode=java