设计模式--备忘录模式&状态模式

142 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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);

![image-20220620133627190.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2dc433e940d84797be39db3af00de8f5~tplv-k3u1fbpfcp-watermark.image?)
    }

}

状态模式

状态模式(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);
    }
}

image-20220621221729868.png

小结:

似乎和策略模式没啥区别,策略模式主动方在策略转发器,根据不同条件设置不同的策略,执行不同的算法,策略与策略之间是独立的,且策略的初始化状态由调用者决定。而状态模式主动方在状态,状态可以主动的修改上下文Context,并且状态与状态之间一般存在关联性。

订单的例子

一件商品从下单到客户手中存在着许多状态,这里面就涉及不同状态需要执行不同操作,且状态的跟新依赖于上一个状态的状态。所以这里策略模式不适用,策略模式无法自动的去更新状态。

订单状态:支付--》发货--〉收货--〉完成

Spring提供的状态机