这里写自定义目录标题
状态模式介绍
一、什么是状态模式?
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
状态模式也称状态机(State Machine)、对象行为型态。简单一句话解释这个设计模式就是:用对象定义具体状态,调用时指向具体状态对象的方法。
二、使用介绍
意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中包含大量与对象状态有关的条件语句。
如何解决:将各种具体的状态类抽象出来。
关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。
注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
三、为什么我们需要它?(适用场景是什么)
业务中免不了不同状态做不同处理的代码,简单情况下我们只需要用if-else,switch-case就可以实现。以下情况,请考虑使用状态机模式:
从1到5,越往后的情况越适用。
1.if后面的条件语句长,过长的条件使得代码阅读性差,更糟糕的是过多条件严重妨碍梳理逻辑。
2.if-else数量多,与第一条有相似之处,过多的情况对于梳理代码流程是不利的,数量过多之后代码累赘加剧。
3.if-else中的操作代码多且复杂,这将使得方法体变得极其庞大,往往使得几个if-else之间相隔天涯,对于把握代码全局是不利的。
4.if,if-else,else if...逻辑关系复杂,逻辑关系复杂往往捋一遍不够,多捋几遍就会绕进去,写出来代码也不容易发现隐患,或者往往要调试很久才发现漏掉的情况。
5.对于这部分的需求改动频繁,如果有之前的不适之症,加上这个,就不解释了。
小结 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。
四、优缺点
优点:
1.代码结构化,易于维护、扩展。
2.每个状态只需要关心自己内部的实现,而不会影响到其他的,耦合降低。
缺点:
1.有多少的状态就得有多少的类,因此会创建大量的类。
2.代码结构变得复杂,不再是单个类中写满逻辑。
五、怎么实现
实现方式有三部分:
1. 状态拥有者的实体模型。
2. 状态接口(也可使用抽象类),定义业务方法。
3. 状态的各个具体实现类,分别实现业务方法。
六、一个简单的地铁运行状态的例子。
第1部分 实体模型的代码
第2部分 状态接口的代码
第3部分 状态的各个具体实现类的代码
这里只贴出了其中两个具体状态的实现类,其他的状态实现同理。
第4部分 最后是测试类:
七、总结:
1.状态机模式:允许对象在内部状态改变时改变它的行为,对象看起来就好像修改了它的类(每个状态可以做出不一样的动作);
2.拥有多个状态的对象(Context)只需要实现需要的操作,每次接收输入的时候(request方法调用),只需要交给当前的状态去处理,而每个状态不需要知道自己之前的状态是什么,只需要知道接收到什么样的输入(或者没输入)而做出相应的操作和自己下一个状态是什么即可;
3.适当的画出系统的状态转换图,可以更清晰地实现系统状态机。
项目开发,单独的状态模式不适用我们的当前的合同状态的流转,我们采用策略模式+状态模式的方式实现
`public interface ContractState {
String CONTRACT_STATE_PREFIX = "ContractState-";
/**
* 0 删除无效状态
* @param contract
*/
default void inActive(Contract contract) {
}
/**
* 1 待发起 待签约
* @param contract
*/
default void waitingForLaunch(Contract contract) {
}
/**
* 2 正常合同,入场通过
* @param contract
*/
default void active(Contract contract) {
}
。。。。
}`
`public class ContractStatesMachine {
private ContractState currentState;
public ContractState getCurrentState(ContractStatus contractStatus) {
currentState = PlatformContext.getComponent(ContractState.CONTRACT_STATE_PREFIX + contractStatus.name());
if (currentState == null) {
currentState = PlatformContext.getComponent(ContractState.CONTRACT_STATE_PREFIX + ContractStatus.INACTIVE.name());
}
return currentState;
}
public void inactive(Contract contract) {
currentState.inActive(contract);
}
public void waitingForLaunch(Contract contract) {
currentState.waitingForLaunch(contract);
}
public void active(Contract contract) {
currentState.active(contract);
}
。。。
}`
`public class ContractStatesServiceImpl {
// 状态的默认实现父类
private static final Logger LOGGER = LoggerFactory.getLogger(ContractStatesServiceImpl.class);
public List<Long> getContractNewtApartments(Contract contract) {
return null;
}
。。。
}`
`
@Component(ContractState.CONTRACT_STATE_PREFIX + “ACTIVE”)
public class ActiveState extends ContractStatesServiceImpl implements ContractState {
private static final Logger LOGGER = LoggerFactory.getLogger(ActiveState.class);
//拥有一个合同对象,用于更新合同当前状态
ContractStatesMachine contractMachine;
public ActiveState(ContractStatesMachine contractMachine) {
this.contractMachine = contractMachine;
}
@Override
public void expired(Contract contract) {
LOGGER.info("ActiveState to EXPIRED, contractId: {}!", contract.getId());
// 变更导致父合同过期
contract.setStatus(ContractStatus.EXPIRED.getCode());
}
@Override
public void history(Contract contract) {
LOGGER.info("ActiveState to HISTORY, contractId: {}!", contract.getId());
contract.setStatus(ContractStatus.HISTORY.getCode());
// 父合同失效,以前生效以前占用,现在不占用了,费用明细账单处理,切分
// 客户id,合同id,
// 房源id, 占用时间段,房源状态
List<Long> apartmentIds = getContractNewtApartments(contract);
updateCustomerAndApartmentRelationship(contract, apartmentIds, AddressMappingStatus.RENT, contract.getContractStartDate(), contract.getContractEndDate());
}
@Override
public void waitingForLaunch(Contract contract) {
LOGGER.info("ActiveState to WAITING_FOR_LAUNCH, contractId: {}!", contract.getId());
contract.setStatus(ContractStatus.WAITING_FOR_LAUNCH.getCode());
List<Long> apartmentIds = getContractNewtApartments(contract);
deleteCustomerAndApartmentRelationship(contract, apartmentIds, AddressMappingStatus.FREE, contract.getContractStartDate(), contract.getContractEndDate());
}
}`
调用 contractStateMachine.getCurrentState(ContractStatus.WAITING_FOR_LAUNCH).waitingForApproval(contract);