持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第32天,点击查看活动详情。
备忘录模式&状态模式
备忘录模式存在一个备忘录类,用于存储待备忘对象的一些属性,这样可以在适当时机撤销或者回滚状态。状态模式存在一个代表状态的属性,改变状态的属性,可以改变其行为,如此可以动态的通过修改对象状态来控制其行为。
备忘录模式和状态模式一般都会结合使用,在某个状态时记录当前状态下的信息,状态模式和备忘录模式结合使用可以很好地记录状态,在特定条件下记录、撤销状态。
备忘录模式
备忘录模式(Memento Pattern),用于保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为模式。
备忘录模式也可以叫备份模式。
涉及角色:
- 原始类:(Original),包含一些属性,负责创建备忘录,且可以自己决定保存哪些状态。
- 备忘录类:(Memento)
- 管理类:(Storage),存储着备忘录信息的类
实现
创建原始类:
@Accessors(chain = true)
@AllArgsConstructor
@Data
@ToString
public class Original {
/**
* 状态,决定保存这个状态
*/
String state;
/**
* 状态对应数据
*/
String value;
/**
* 备忘
* @return
*/
public Memento createMemento() {
return new Memento(state, value);
}
/**
* 恢复
* @param memento
*/
public void resStore(Memento memento) {
BeanUtils.copyProperties(memento.reStore(), this);
}
}
创建备忘录:
存储某个状态,并将状态对应值记录进单例,使用单例模拟数据库
public class Memento {
String state;
public Memento(String state, String value) {
this.state = state;
SignalDatabase.getInstance().add(state, value);
}
0、+·
public String getState() {
return state;
}
/**
* 更改某个状态的值
*
* @param value
*/
public void setState(String value) {
SignalDatabase.getInstance().add(state, value);
}
//恢复
public Original reStore() {
Object value = SignalDatabase.getInstance().getValue(state);
return new Original(state, (String) value);
}
}
使用单例模拟数据库:
public class SignalDatabase {
private Map<String, Object> map = new HashMap<>();
private static class SingletonHolder {
private static final SignalDatabase signalDatabase = new SignalDatabase();
}
private SignalDatabase() {
}
public static SignalDatabase getInstance() {
return SingletonHolder.signalDatabase;
}
/**
* 保存状态
* @param state
* @param value
*/
void add(String state, Object value) {
map.put(state, value);
}
Object getValue(String state) {
return map.get(state);
}
}
管理备忘:
public class CareMaker {
private List<Memento> mementoList = new ArrayList<>();
public void store(Memento memento) {
mementoList.add(memento);
}
public Memento getMemento(int index) {
return mementoList.get(index);
}
}
测试:
public class Client {
public static void main(String[] args) {
CareMaker careMaker = new CareMaker();
Original original1 = new Original("#01", "状态一");
System.out.println("original1" + "原始状态:=>" + original1);
//保存状态
careMaker.store(original1.createMemento());
original1.setValue("状态一被修改");
original1.setState("#011");
System.out.println("original1" + "状态被修改:=>" + original1);
original1.resStore(careMaker.getMemento(0));
System.out.println("original1" + "状态恢复:=>" + original1);

}
}
状态模式
状态模式(State Pattern),对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
设计角色:
- Context :上下文,定义客户端需要的接口。其内部维护了一个状态,并负责切换状态。
- State:抽象状态,定义一个接口,抽象了对象特定状态下的行为
- ConcreateState:具体状态,实现抽象状态的行为,并在特定情况下切换状态
简单实现
定义抽象状态:
某个状态对应需要执行的方法 持有上下文对象,可在特定情况切换状态
public interface State {
/**
* 某个状态对应需要执行的方法
* 持有上下文对象,可在特定情况切换状态
* @param context
*/
void doAction(Context context);
}
定义具体实现状态:
public class StopState implements State{
@Override
public void doAction(Context context) {
context.setState(this);
System.out.println(this.getClass().getName());
}
}
public class StartState implements State{
@Override
public void doAction(Context context) {
context.setState(this);
System.out.println(this.getClass().getName());
}
}
上下文对象:
组合状态,并负责切换状态。
@Data
public class Context {
/**
* 上下文包含了state对象
*/
private State state;
}
测试:
public class StateTest {
public static void main(String[] args) {
final Context context = new Context();
final State startState = new StartState();
final State stopState = new StopState();
startState.doAction(context);
stopState.doAction(context);
}
}
小结:
似乎和策略模式没啥区别,策略模式主动方在策略转发器,根据不同条件设置不同的策略,执行不同的算法,策略与策略之间是独立的,且策略的初始化状态由调用者决定。而状态模式主动方在状态,状态可以主动的修改上下文Context,并且状态与状态之间一般存在关联性。
订单的例子
一件商品从下单到客户手中存在着许多状态,这里面就涉及不同状态需要执行不同操作,且状态的跟新依赖于上一个状态的状态。所以这里策略模式不适用,策略模式无法自动的去更新状态。
订单状态:支付--》发货--〉收货--〉完成