状态模式:封装数据的状态流转逻辑
状态模式里,非常重要的一点就是将状态之间流转的逻辑,封装在Context类里面。本来可能需要调用方自己维护复杂的状态流转逻辑,流转到不同的状态之后,执行状态对应的代码逻辑。

需求背景:
上线一个商品的流程包括:
编辑,审核,上架三个过程。处于每个流程时,状态属性
是不一样的

定义一个商品状态接口GoodsState ,来封装聚合状态的流转与判断:
对于商品所处于四种状态分别给四种实现:
待审核 WaitForApproveGoodsState、
审核未通过 ApproveRejectGoodsState、
审核通过(待上架)WaitForPutOnShelvesGoodsState、
已上架 PuttedOnShelvesGoodsState

GoodsState


/**
 * 商品状态接口
 * @author 
 *
 */
public interface GoodsState {
	/**
	 * 执行商品流转到当前状态来的业务逻辑
	 * @param goods 商品
	 * @throws Exception
	 */
	void doTransition(GoodsDTO goods) throws Exception;

	/**
	 * 判断当前商品能否执行编辑操作
	 * @param goods 商品
	 * @return 能否执行编辑操作
	 */
	Boolean canEdit(GoodsDTO goods) throws Exception;


	/**
	 * 判断能否执行审核操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canApprove(GoodsDTO goods) throws Exception;


	/**
	 * 判断能否执行上架操作
	 * @param goods 商品
	 * @return 能否执行上架操作
	 * @throws Exception
	 */
	Boolean canPutOnShelves(GoodsDTO goods) throws Exception;


	/**
	 * 判断能否执行下架操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canPullOffShelves(GoodsDTO goods) throws Exception;

	/**
	 * 能否执行删除操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canRemove(GoodsDTO goods) throws Exception;
}


/**
 * 已上架状态
 * @author 
 *
 */
@Component
public class PuttedOnShelvesGoodsState implements GoodsState {
	/**
	 * 日期辅助组件
	 */
	@Autowired
	private DateProvider dateProvider;
	/**
	 * 商品管理DAO组件
	 */
	@Autowired
	private GoodsDAO goodsDAO;

	/**
	 * 执行商品流转到当前状态来的业务逻辑
	 *
	 * @param goods 商品
	 * @throws Exception
	 */
	@Override
	public void doTransition(GoodsDTO goods) throws Exception {
		goods.setStatus(GoodsStatus.PUTTED_ON_SHELVES);
		goods.setGmtModified(dateProvider.getCurrentTime());
		goodsDAO.updateStatus(goods.clone(GoodsDO.class));
	}

	@Override
	public Boolean canEdit(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canApprove(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canPutOnShelves(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canPullOffShelves(GoodsDTO goods) throws Exception {
		return true;
	}

	@Override
	public Boolean canRemove(GoodsDTO goods) throws Exception {
		return false;
	}
}


/**
 * 待审核商品状态
 * @author zhonghuashishan
 *
 */
@Component
public class WaitForApproveGoodsState implements GoodsState {
	/**
	 * 商品管理DAO组件
	 */
	@Autowired
	private GoodsDAO goodsDAO;
	/**
	 * 日期辅助组件
	 */
	@Autowired
	private DateProvider dateProvider;


	@Override
	public void doTransition(GoodsDTO goods) throws Exception {
		goods.setStatus(GoodsStatus.WAIT_FOR_APPROVE);
		goods.setGmtModified(dateProvider.getCurrentTime());
		goodsDAO.updateStatus(goods.clone(GoodsDO.class));
	}

	@Override
	public Boolean canEdit(GoodsDTO goods) throws Exception {
		return true;
	}

	@Override
	public Boolean canApprove(GoodsDTO goods) throws Exception {
		return true;
	}

	@Override
	public Boolean canPutOnShelves(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canPullOffShelves(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canRemove(GoodsDTO goods) throws Exception {
		return true;
	}
}


/**
 * 待上架状态
 * @author zhonghuashishan
 *
 */
@Component
public class WaitForPutOnShelvesGoodsState implements GoodsState {

	/**
	 * 日期辅助组件
	 */
	@Autowired
	private DateProvider dateProvider;
	/**
	 * 商品管理DAO组件
	 */
	@Autowired
	private GoodsDAO goodsDAO;


	@Override
	public void doTransition(GoodsDTO goods) throws Exception {
		goods.setStatus(GoodsStatus.WAIT_FOR_PUT_ON_SHELVES);
		goods.setGmtModified(dateProvider.getCurrentTime());
		goodsDAO.updateStatus(goods.clone(GoodsDO.class));
	}

	@Override
	public Boolean canEdit(GoodsDTO goods) throws Exception {
		return true;
	}

	@Override
	public Boolean canApprove(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canPutOnShelves(GoodsDTO goods) throws Exception {
		return true;
	}

	@Override
	public Boolean canPullOffShelves(GoodsDTO goods) throws Exception {
		return false;
	}

	@Override
	public Boolean canRemove(GoodsDTO goods) throws Exception {
		return true;
	}

}


定义一个商品状态管理的接口:


/**
 * 商品状态管理器接口
 * @author 
 *
 */
public interface GoodsStateManager {
	/**
	 * 创建一个商品
	 * @param goods
	 * @throws Exception
	 */
	void create(GoodsDTO goods) throws Exception;

	/**
	 * 当前这个商品能否执行编辑操作
	 * @param goods 商品
	 * @return 能否执行编辑操作
	 * @throws Exception
	 */
	Boolean canEdit(GoodsDTO goods) throws Exception;

	/**
	 * 执行编辑商品的操作
	 * @param goods 商品
	 * @throws Exception
	 */
	void edit(GoodsDTO goods) throws Exception;

	/**
	 * 判断能否执行审核操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canApprove(GoodsDTO goods) throws Exception;

	/**
	 * 执行审核操作
	 * @param goods
	 * @param approveResult
	 * @throws Exception
	 */
	void approve(GoodsDTO goods, Integer approveResult) throws Exception;

	/**
	 * 判断能否执行上架操作
	 * @param goods 商品
	 * @return 能否执行上架操作
	 * @throws Exception
	 */
	Boolean canPutOnShelves(GoodsDTO goods) throws Exception;

	/**
	 * 执行上架操作
	 * @param goods
	 * @throws Exception
	 */
	void putOnShelves(GoodsDTO goods) throws Exception;


	/**
	 * 判断能否执行下架操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canPullOffShelves(GoodsDTO goods) throws Exception;


	/**
	 * 执行下架操作
	 * @param goods 商品
	 * @throws Exception
	 */
	void pullOffShelves(GoodsDTO goods) throws Exception;


	/**
	 * 能否执行删除操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	Boolean canRemove(GoodsDTO goods) throws Exception;

}


/**
 * 商品状态管理器实现
 * @author 
 *
 */
@Component
public class GoodsStateManagerImpl implements GoodsStateManager {

	/**
	 * 待审核状态
	 */
	@Autowired
	private WaitForApproveGoodsState waitForApproveGoodsState;
	/**
	 * 待上架状态
	 */
	@Autowired
	private WaitForPutOnShelvesGoodsState waitForPutOnShelvesGoodsState;
	/**
	 * 审核未通过状态
	 */
	@Autowired
	private ApproveRejectGoodsState approveRejectGoodsState;
	/**
	 * 已上架状态
	 */
	@Autowired
	private PuttedOnShelvesGoodsState puttedOnShelvesGoodsState;
	/**
	 * 商品状态工厂
	 */
	@Autowired
	private GoodsStateFactory goodsStateFactory;


	/**
	 * 创建一个商品
	 * @param goods
	 * @throws Exception
	 */
	@Override
	public void create(GoodsDTO goods) throws Exception {
		waitForApproveGoodsState.doTransition(goods);
	}

	@Override
	public Boolean canEdit(GoodsDTO goods) throws Exception {
		GoodsState state = goodsStateFactory.get(goods);
		return state.canEdit(goods);
	}

	@Override
	public void edit(GoodsDTO goods) throws Exception {
		waitForApproveGoodsState.doTransition(goods);
	}

	@Override
	public Boolean canApprove(GoodsDTO goods) throws Exception {
		GoodsState state = goodsStateFactory.get(goods);
		return state.canApprove(goods);
	}

	@Override
	public void approve(GoodsDTO goods, Integer approveResult) throws Exception {
		if (ApproveResult.APPROVE_PASS.equals(approveResult)) {
			waitForApproveGoodsState.doTransition(goods);
		}  else if (ApproveResult.APPROVE_REJECT.equals(approveResult)) {
			approveRejectGoodsState.doTransition(goods);
		}
	}

	@Override
	public Boolean canPutOnShelves(GoodsDTO goods) throws Exception {
		GoodsState state = goodsStateFactory.get(goods);
		return state.canPutOnShelves(goods);
	}

	@Override
	public void putOnShelves(GoodsDTO goods) throws Exception {
		puttedOnShelvesGoodsState.doTransition(goods);
	}

	@Override
	public Boolean canPullOffShelves(GoodsDTO goods) throws Exception {
		GoodsState state = goodsStateFactory.get(goods);
		return state.canPullOffShelves(goods);
	}

	@Override
	public void pullOffShelves(GoodsDTO goods) throws Exception {
		waitForApproveGoodsState.doTransition(goods);
	}

	@Override
	public Boolean canRemove(GoodsDTO goods) throws Exception {
		GoodsState state = goodsStateFactory.get(goods);
		return state.canRemove(goods);
	}
}


封装一个商品状态工厂、根据商品状态code获取相应的状态实现类,然后根据实现获取不同状态的可编辑状态。

/**
 * 商品状态工厂
 * @author
 *
 */
@Component
public class GoodsStateFactory {
	/**
	 * 待审核状态
	 */
	@Autowired
	private WaitForApproveGoodsState waitForApproveGoodsState;
	/**
	 * 待上架状态
	 */
	@Autowired
	private WaitForPutOnShelvesGoodsState waitForPutOnShelvesGoodsState;
	/**
	 * 审核未通过状态
	 */
	@Autowired
	private ApproveRejectGoodsState approveRejectGoodsState;
	/**
	 * 已上架状态
	 */
	@Autowired
	private PuttedOnShelvesGoodsState puttedOnShelvesGoodsState;
	/**
	 * 默认商品状态
	 */
	@Autowired
	private DefaultGoodsState defaultGoodsState;

	/**
	 * 获取商品对应的状态组件
	 * @param goods 商品
	 * @return 状态组件
	 * @throws Exception
	 */

	public GoodsState get(GoodsDTO goods) {
		if(GoodsStatus.WAIT_FOR_APPROVE.equals(goods.getStatus())) {
			return waitForApproveGoodsState;
		} else if(GoodsStatus.WAIT_FOR_PUT_ON_SHELVES.equals(goods.getStatus())) {
			return waitForPutOnShelvesGoodsState;
		} else if(GoodsStatus.APPROVE_REJECT.equals(goods.getStatus())) {
			return approveRejectGoodsState;
		} else if(GoodsStatus.PUTTED_ON_SHELVES.equals(goods.getStatus())) {
			return puttedOnShelvesGoodsState;
		} else {
			return defaultGoodsState;
		}
	}
	
}


最终使用,在最后商品编辑实现类种使用上述的状态模式:

/**
 * 商品管理service组件
 * @author 
 *
 */
@Service
@Transactional
public class GoodsServiceImpl implements GoodsService {

	/**
	 * 商品管理DAO组件
	 */
	@Autowired
	private GoodsDAO goodsDAO;
	/**
	 * 商品状态管理器
	 */
	@Autowired
	private GoodsStateManager goodsStateManager;
	/**
	 * 商品图片管理DAO
	 */
	@Autowired
	private GoodsPictureDAO goodsPictureDAO;
	/**
	 * 商品详情管理DAO
	 */
	@Autowired
	private GoodsDetailDAO goodsDetailDAO;
	/**
	 * 商品详情图片管理DAO
	 */
	@Autowired
	private GoodsDetailPictureDAO goodsDetailPictureDAO;
	/**
	 * 商品属性值管理DAO
	 */
	@Autowired
	private GoodsPropertyValueDAO goodsPropertyValueDAO;
	/**
	 * 商品sku管理DAO
	 */
	@Autowired
	private GoodsSkuDAO goodsSkuDAO;
	/**
	 * 商品sku属性值管理DAO
	 */
	@Autowired
	private GoodsSkuSalePropertyValueDAO goodsSkuSalePropertyValueDAO;
	
	/**
	 * 分页查询商品
	 * @param query 查询条件
	 * @return 商品
	 */
	public List<GoodsDTO> listByPage(GoodsQuery query) throws Exception {
		return ObjectUtils.convertList(goodsDAO.listByPage(query), GoodsDTO.class); 
	}
	
	/**
	 * 根据id查询商品
	 * @param id 商品id
	 * @return 商品
	 */
	public GoodsDTO getById(Long id) throws Exception {
		return goodsDAO.getById(id).clone(GoodsDTO.class);
	}
	
	/**
	 * 新增商品
	 * @param goods 商品
	 */
	public Long save(GoodsDTO goods) throws Exception {
		Long goodsId = goodsDAO.save(goods.clone(GoodsDO.class)); 
		goodsStateManager.create(goods); 
		return goodsId;
	}
	
	/**
	 * 更新商品
	 * @param goods 商品
	 */
	public Boolean update(GoodsDTO goods) throws Exception {
		if(!goodsStateManager.canEdit(goods)) {
			return false;
		}
		
		goodsDAO.update(goods.clone(GoodsDO.class));  
		goodsStateManager.edit(goods); 
		
		return true;
	}
	
	/**
	 * 审核商品
	 * @param goods 商品
	 * @return 处理结果
	 * @throws Exception
	 */
	public Boolean approve(GoodsDTO goods, Integer approveResult) throws Exception {
		if(!goodsStateManager.canApprove(goods)) {
			return false;
		}
		goodsStateManager.approve(goods, approveResult);
		return true;
	}
	
	/**
	 * 执行上架操作
	 * @param goods
	 * @return
	 * @throws Exception
	 */
	public Boolean putOnShelves(GoodsDTO goods) throws Exception {
		if(!goodsStateManager.canPutOnShelves(goods)) {
			return false;
		}
		goodsStateManager.putOnShelves(goods);
		return true;
	}
	
	/**
	 * 执行下架操作
	 * @param goods 商品
	 * @return
	 * @throws Exception
	 */
	public Boolean pullOffShelves(GoodsDTO goods) throws Exception {
		if(!goodsStateManager.canPullOffShelves(goods))   {
			return false;
		}
		goodsStateManager.pullOffShelves(goods); 
		return true;
	}
	
	/**
	 * 执行删除操作
	 * @param goodsId
	 * @return
	 * @throws Exception
	 */
	public Boolean remove(Long id) throws Exception {
		GoodsDTO goods = goodsDAO.getById(id).clone(GoodsDTO.class);
		
		if(!goodsStateManager.canRemove(goods)) {
			return false;
		}
		
		goodsPictureDAO.removeByGoodsId(id); 
		
		GoodsDetailDO goodsDetail = goodsDetailDAO.getByGoodsId(id);
		goodsDetailPictureDAO.removeByGoodsDetailId(goodsDetail.getId());  
		goodsDetailDAO.remove(goodsDetail.getId()); 
		
		goodsPropertyValueDAO.removeByGoodsId(id); 
		
		List<GoodsSkuDO> goodsSkus = goodsSkuDAO.listByGoodsId(id);
		for(GoodsSkuDO goodsSku : goodsSkus) {
			goodsSkuSalePropertyValueDAO.removeByGoodsSkuId(goodsSku.getId()); 
		}
		goodsSkuDAO.removeByGoodsId(id); 
		
		return true;
	}
	
}