最近学完《Head first to Design Pattern》这本书,正好打算利用业余时间重写公司的一个项目,就想拿着重建项目的机会练下手,此文用来记录下遇到的坑和解决方案。java
首先介绍下项目背景,一个很简单的流程,对象是Project,有一个标记审批状态的字段为status,根据业务流程,转到不一样的阶段,每一个阶段对应一个值,很适合用状态模式来实现。设计模式
贴一下设计模式书中的图:里面的术语下文要用到。app
首先先定义接口,并写好实现类,而后把Context也写好,基本上都是照抄书上代码,毋庸多言。我惟一作了改动的是把State接口改为了普通类,底下的ConcreateState用的覆盖的方法。默认父类方法里都是抛出UnsupportedOperationException。这样若是调用子类没有实现的方法时,会自动抛出不支持的操做。框架
贴一下个人类图:ide
那么这个状态机是如何跟project的状态挂接起来的呢,书中的糖果机只一个,而project有不少个,怎么让每一个project都能用上状态模式呢?我绕了不少弯路,才发现以前的误区,project就是糖果,status就是count,状态机不须要有不少个,只要能处理这个状态就好了。this
那么context的构造器方法就能够改形成传入project对象的构造器设计
public StateContext(Project project) { initialState = new InitialState(this); approvalPendingState = new ApprovalPendingState(this); approvalFailState = new ApprovalFailState(this); biddingState = new BiddingState(this); bidFailState = new BidFailState(this); implementState = new ImplementState(this); finishState = new FinishState(this); closedState = new ClosedState(this); switch (project.getStatus()) { case Project.INITIAL: state = initialState; break; case Project.APPROVAL_PENDING: state = approvalPendingState; break; case Project.APPROVAL_FAIL: state = approvalFailState; break; case Project.BIDDING: state = biddingState; break; case Project.BID_FAIL: state = bidFailState; break; case Project.IMPLEMENT: state = implementState; break; case Project.FINISH: state = finishState; break; case Project.CLOSED: state = closedState; break; } }
而后把Project传入每一个状态类,code
public Project apply(Project project){ return state.apply(project); }
在状态类内改变后再返回。 对象
@Override public Project apply(Project project) { project.setStatus(Project.APPROVAL_PENDING); stateContext.setState(stateContext.getApprovalPendingState()); return project; }
在Controller里以下图调用接口
try { StateContext stateContext = new StateContext(project); projectService.save(stateContext.apply(project)); addMessage(redirectAttributes, "保存项目成功"); } catch (UnsupportedOperationException e) { addMessage(redirectAttributes, "当前阶段不支持此操做"); }
以前我曾经想过把Service直接放到每一个Concrete动做类里去,可是存在的问题是无法注入Service,由于都是构造方法构造出来的,而后我又改造构造方法,所有换成注入的,可是在注入Context里保存当前状态的state对象时遇到问题了,state是可变的,无法肯定应该注入哪个。后来全又改回书上的写法了。
另外状态模式也有框架,是在sprngboot下的,之后有机会能够尝试一下。最后写流程仍是提倡使用工做流,使用状态模式的问题是类爆炸太多,写起来也不方便。