You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

备忘录模式:如何兼顾Memento对象的封装性与复用性?

备忘录模式:封装与复用的解决方案

问题代码

class Originator {
   private String state;
   Originator(String state) {
        this.state = state;
   }
   
   public void setState(String newState) {
        this.state = newState;
   }
   
   public Memento createMemento() {
        return new Memento(state);
   }
   
   public void restoreState(Memento memento) {
        // HOW to access private state of memento??
   }
}


class Memento {
   private String state;
   Memento(String state) {
        this.state = state;
   }
}


class CareTaker {
    public static void main(String[] args) {
        Originator originator = new Originator("state");
        Memento memento = originator.createMemento();
        
        originator.setState("new state");
        originator.restoreState(memento);
    }
}

问题描述

实现备忘录模式时,将Memento类的state设为私有以阻止Caretaker访问,但导致Originator也无法访问Memento的私有state。曾考虑三种方案但均有弊端:

  • 将Memento的state设为公有:违背内部状态封装原则。
  • 将Memento设为Originator内部类:Memento会与Originator绑定,无法被其他Originator复用。
  • Memento构造方法传入Originator引用:Memento会绑定单个Originator对象,无法复用。

需要一种既能遵循封装原则,又支持Memento对象复用的解决方案。

解决方案:接口隔离+包级访问控制

这种方案通过接口隐藏Memento的内部细节,同时利用包级访问权限让Originator合法访问状态,既保证封装性,又支持Memento跨Originator复用。

代码实现

// 对外暴露的空接口,Caretaker仅能持有该类型,无法访问内部状态
interface Memento {
}

class Originator {
    private String state;

    Originator(String state) {
        this.state = state;
    }

    public void setState(String newState) {
        this.state = newState;
    }

    public Memento createMemento() {
        return new ConcreteMemento(state);
    }

    public void restoreState(Memento memento) {
        // 向下转型为具体实现类,同包下可访问其包级方法
        this.state = ((ConcreteMemento) memento).getState();
    }
}

// 包级访问的具体备忘录类,仅同包内的类可访问getState方法
class ConcreteMemento implements Memento {
    private String state;

    ConcreteMemento(String state) {
        this.state = state;
    }

    // 包级权限方法,仅同包类可调用
    String getState() {
        return state;
    }
}

class CareTaker {
    public static void main(String[] args) {
        Originator originator = new Originator("state");
        Memento memento = originator.createMemento();
        
        originator.setState("new state");
        originator.restoreState(memento);
    }
}

方案说明

  1. 接口隔离:对外仅暴露Memento空接口,Caretaker只能持有该接口实例,无法直接访问ConcreteMemento的内部状态或方法,保证了封装性。
  2. 包级访问控制:ConcreteMemento及其getState方法均为包级权限,同包内的所有Originator类(包括不同的Originator实现)都可以调用该方法恢复状态,实现了Memento的复用。
  3. 灵活性:如果需要跨包复用,可将ConcreteMemento的访问权限调整为protected,并让跨包的Originator继承自同一个基类,或者利用Java 9+的模块系统指定友元模块开放权限,包级访问是最简洁的通用实现方式。

内容的提问来源于stack exchange,提问作者Nishant Chauhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:16:06