使用模板方法模式时,父类会抽取大量的公共逻辑。子类只需要实现个性化需求即可。
难点:当某个子类在父类的钩子方法A中查询出X字段,需要传递到父类的钩子方法B中。但是方法的参数对象中没有X字段。
难点在于:子类需要修改父类参数列表,但是不符合重写规则,在编译的时候会失败。
解决方案:
- 去修改父类dto对象。(不满足开闭原则,且其他子类不需要X字段,会造成父类dto太冗余);
- 使用ThreadLocal传递。(契约性低,无法约束,容易忘记);
- 多态+引用传递,子类在钩子方法A中创建dto子类对象,向下传递,在钩子方法B中强转。(可读性差);
有没有一种更加巧妙的实现方式?
有的,就是利用泛型的
语法来进行实现。这样父类公共逻辑可以使用Dto对象,子类个性化对象可以去扩展Dto对象。
代码参考:
/**
* T 是PublishReq类或子类: 前端发送的请求对象;
* V 是PublishDto类或子类:在"预处理器"中T会转换为V,V会在"持久化处理器"中完成入库等操作;
* R 是PublishResp类或子类:对外输出;
*/
public interface PublishService {
/**
* 任务发布
*/
R publish(T req, R resp);
}
抽象父类抽取公共逻辑:
/**
* 模板方法模式,注意:模板父类定义的所有方法入参、出参均是泛型类型。
* 这就保证了子类扩展时,可以使用个性化的实现。
*
* 注:方法出参为void,而值改变依赖的是"参数的 引用传递"来完成变化。
*/
public abstract class AbstractPublishService implements PublishService {
/**
* 发布事件的公共逻辑...
*/
@Override
public R publish(T req, R resp) {
//1. 校验逻辑
validatorHandler(req, resp);
//2. 预处理器
V dto = preHandler(req, resp);
//3. 持久化处理器
persistenceHandler(req, dto, resp);
//4. 后置处理器
postHandler(req, dto, resp);
return resp;
}
/*************************************************************
* 1. 校验处理器(校验T)
************************************************************/
protected void validatorHandler(T req, R resp) {
//公共校验
if (req.getTaskName() == null) {
throw new IllegalArgumentException("taskName is not null");
}
//个性化校验的钩子方法
customValidatorHandler(req, resp);
}
/**
* 子类需要实现个性化校验逻辑的钩子方法
*/
protected void customValidatorHandler(T req, R resp) {
}
/*************************************************************
* 2. 预处理器(T转换为将要入库的V)
************************************************************/
protected V preHandler(T req, R resp) {
//查询数据库,填充V对象
V dto = buildPublishDto(req, resp);
//填充公共字段(查询数据库)
dto.setPlanName("练习");
//个性化逻辑
customPreHandler(req, dto, resp);
return dto;
}
/**
* 构建Dto对象
*/
protected abstract V buildPublishDto(T req, R resp);
/**
* 子类需要实现个性化逻辑的钩子方法
*/
protected void customPreHandler(T req, V dto, R resp) {
}
/*************************************************************
* 3. 持久化处理器(V入库)
************************************************************/
protected void persistenceHandler(T req, V dto, R resp) {
//公共的持久化逻辑
//todo
customPersistenceHandler(req, dto, resp);
}
protected void customPersistenceHandler(T req, V dto, R resp) {
}
/*************************************************************
* 4. 持久化处理器(R处理,消息事件等...)
************************************************************/
protected void postHandler(T req, V dto, R resp) {
//发布成功后,发布事件消息...
}
}
子类个性化参数对象:
/**
* 可以看到, T为WordPublishReq,V为WordPublishDto。子类重写的方法签名已经为个性化的。由此可以灵活的扩展。
*/
public class WordPublishService extends AbstractPublishService {
/**
* 对象转换,将WordPublishReq转换为要持久化的WordPublishDto对象、
*
*/
@Override
protected WordPublishDto buildPublishDto(WordPublishReq req, PublishResp resp) {
return null;
}
/**
* 个性化持久化处理
*/
@Override
protected void customPersistenceHandler(WordPublishReq req, WordPublishDto dto, PublishResp resp) {
super.customPersistenceHandler(req, dto, resp);
//个性化持久化处理
}
}