避免过度使用IllegalStateException:ContentContainer类状态检查优化的设计模式咨询
优化ContentContainer状态检查与异常使用的设计方案
针对你遇到的场景——分片上传未完成时调用transfer会抛出通用的IllegalStateException,同时希望避免每次调用方法都重复执行状态判断、减少通用异常的过度使用,状态模式(State Pattern) 是非常契合的解决方案。它能将不同状态下的行为逻辑封装到独立类中,让状态切换和行为调用更清晰,彻底消除重复的状态检查代码。
核心思路
状态模式的核心是把对象每个状态对应的行为都封装成单独的状态类,原对象(ContentContainer)不再负责判断状态和处理不同状态下的行为,而是将所有操作委托给当前持有的状态实例。这样一来:
- 不用再写一堆
if (state != XXX)的冗余判断语句 - 每个状态的行为逻辑被隔离,维护和扩展更方便
- 可以用更友好的方式处理非法操作(比如返回布尔值、抛出语义更明确的业务异常),而不是滥用通用的
IllegalStateException
具体实现步骤
1. 定义抽象状态接口
首先创建一个接口,统一规定不同状态下需要处理的行为:
public interface ContentStateHandler { // 添加分片,返回操作是否成功 boolean addContentPart(ContentContainer container, ContentPart part); // 执行传输,返回操作是否成功 boolean transfer(ContentContainer container); // 获取当前状态对应的枚举值(用于持久化) ContentState getState(); }
2. 实现各具体状态类
为每个ContentState枚举值创建对应的状态类,只处理该状态下允许的操作:
NEW状态(初始状态)
public class NewState implements ContentStateHandler { @Override public boolean addContentPart(ContentContainer container, ContentPart part) { // 初始状态不允许添加分片,返回false return false; } @Override public boolean transfer(ContentContainer container) { // 未开始上传的内容无法传输,返回false return false; } @Override public ContentState getState() { return ContentState.NEW; } }
IN_UPLOAD状态(上传中)
public class InUploadState implements ContentStateHandler { @Override public boolean addContentPart(ContentContainer container, ContentPart part) { container.getParts().add(part); // 检查是否所有分片已上传完成,自动切换状态 if (container.getParts().size() == container.getExpectedParts()) { container.setStateHandler(new UploadFinishedState()); } return true; } @Override public boolean transfer(ContentContainer container) { // 上传中无法执行传输,返回false return false; } @Override public ContentState getState() { return ContentState.IN_UPLOAD; } }
UPLOAD_FINISHED状态(上传完成)
public class UploadFinishedState implements ContentStateHandler { @Override public boolean addContentPart(ContentContainer container, ContentPart part) { // 上传完成后不允许再添加分片,返回false return false; } @Override public boolean transfer(ContentContainer container) { // 执行实际的传输操作 doTransfer(container); // 传输完成后切换到TRANSFER_FINISHED状态 container.setStateHandler(new TransferFinishedState()); return true; } private void doTransfer(ContentContainer container) { // 这里写具体的传输逻辑 } @Override public ContentState getState() { return ContentState.UPLOAD_FINISHED; } }
TRANSFER_FINISHED状态(传输完成)
public class TransferFinishedState implements ContentStateHandler { @Override public boolean addContentPart(ContentContainer container, ContentPart part) { return false; } @Override public boolean transfer(ContentContainer container) { // 已传输完成,无需重复执行 return false; } @Override public ContentState getState() { return ContentState.TRANSFER_FINISHED; } }
3. 修改ContentContainer类
让容器类持有当前状态实例,所有操作都委托给状态类处理:
public class ContentContainer { private enum ContentState { NEW, IN_UPLOAD, UPLOAD_FINISHED, IN_TRANSFER, TRANSFER_FINISHED } // 持久化至Postgres数据库 private UUID uuid; private ContentStateHandler stateHandler; private List<ContentPart> parts; private Integer expectedParts; public ContentContainer() { // 初始状态为NEW this.stateHandler = new NewState(); this.parts = new ArrayList<>(); } // 初始化上传时调用,切换到IN_UPLOAD状态 public void startUpload(Integer expectedParts) { this.expectedParts = expectedParts; this.stateHandler = new InUploadState(); // 持久化状态变更到数据库 } public boolean addContentPart(ContentPart contentPart) { boolean success = stateHandler.addContentPart(this, contentPart); if (success) { // 持久化分片和当前状态到数据库 } return success; } public boolean transfer() { boolean success = stateHandler.transfer(this); if (success) { // 持久化状态变更到数据库 } return success; } // 供状态类访问的getter方法 public List<ContentPart> getParts() { return parts; } public Integer getExpectedParts() { return expectedParts; } public void setStateHandler(ContentStateHandler stateHandler) { this.stateHandler = stateHandler; } // 获取当前状态(用于持久化或外部查询) public ContentState getCurrentState() { return stateHandler.getState(); } }
方案优势
- 消除重复状态检查:所有状态判断逻辑都被封装在对应的状态类中,ContentContainer里再也看不到冗余的状态判断代码,代码更简洁易维护。
- 单一职责原则:容器类只负责维护数据和委托行为,状态的行为逻辑由各自的状态类处理,职责边界更清晰。
- 减少通用异常滥用:原来的代码只要状态不对就抛出
IllegalStateException,现在可以通过返回布尔值让调用方自行处理,或者在状态类中抛出语义更明确的业务异常(比如UploadInProgressException、ContentNotReadyException),让错误处理更精准。 - 易扩展:如果后续需要新增状态(比如
IN_TRANSFER),只需要新增一个状态类实现ContentStateHandler接口即可,无需修改原有代码,符合开闭原则。
内容的提问来源于stack exchange,提问作者user6412004
相关产品推荐
相关产品推荐

