JAVA编程技巧(十)

十、利用设计模式

10.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;   
    }
}

10.2. 建造者模式

建造者模式(Builder Pattern)将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。

普通:

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;   
    }
 
    /** 存储数据 */  
    @Overridepublic 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 表达式,代码较少较简洁。

10.3. 代理模式

Spring 中最重要的代理模式就是 AOP (Aspect-Oriented Programming,面向切面的编程),是使用 JDK 动态代理和 CGLIB 动态代理技术来实现的。

普通:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    /** 用户服务 */  
    @Autowired  
    private UserService userService;
 
    /** 查询用户 */  
    @PostMapping("/queryUser") 
    public Result<?> queryUser(@RequestBody @Valid UserQueryVO query) {
        try {
            PageDataVO<UserVO> pageData = userService.queryUser(query);  
            return Result.success(pageData);    
        } catch (Exception e) {
            log.error(e.getMessage(), e); 
            return Result.failure(e.getMessage());   
        }
    }
    ...
}

精简 1:

基于 @ControllerAdvice 的异常处理:

@RestController
@RequestMapping("/user")
public class UserController {  
    /** 用户服务 */  
    @Autowired   
    private UserService userService;
 
    /** 查询用户 */ 
    @PostMapping("/queryUser")  
    public Result<PageDataVO<UserVO>> queryUser(@RequestBody @Valid UserQueryVO query) {     
        PageDataVO<UserVO> pageData = userService.queryUser(query);   
        return Result.success(pageData);  
    }
    ...
}
 
@Slf4j
@ControllerAdvice
public class GlobalControllerAdvice {  
    /** 处理异常 */ 
    @ResponseBody  
    @ExceptionHandler(Exception.class)   
    public Result<Void> handleException(Exception e) {   
        log.error(e.getMessage(), e);   
        return Result.failure(e.getMessage()); 
    }
}

精简 2:

基于 AOP 的异常处理:

// UserController 代码同 "精简 1"
@Slf4j
@Aspect
public class WebExceptionAspect {
    /** 点切面 */ 
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") 
    private void webPointcut() {}
 
    /** 处理异常 */   
    @AfterThrowing(pointcut = "webPointcut()", throwing = "e") 
    public void handleException(Exception e) {
        Result<Void> result = Result.failure(e.getMessage());    
        writeContent(JSON.toJSONString(result));   
    }
    ...
}
正文完
 0
admin
版权声明:本站原创文章,由 admin 2016-03-04发表,共计6908字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处:https://www.mlzj.net。