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

装饰器模式扩展功能问题:如何调用LockedStack对象的undo方法?

装饰器模式示例的问题分析

这个教材示例的设计确实有问题,或者说它没正确体现装饰器模式的核心原则。

装饰器模式的核心逻辑是:

  • 装饰器和被装饰对象要实现同一个接口(或继承同一抽象类)
  • 所有功能调用都得通过装饰器的公共方法转发,绝对不能直接去访问内部的delegate私有成员

你遇到的问题根源很明确:

  1. 示例违反了封装原则——私有成员本来就是给内部用的,让客户端直接依赖它完全是错误设计
  2. 正确的做法应该是:如果LockedStack支持撤销功能,就暴露undo()公共方法,内部把调用转发给delegate.undo();如果它不允许撤销,那应该屏蔽这个方法,而不是引导你绕过它去碰内部成员

给你一个正确的实现思路参考:

// 抽象栈接口,定义所有需要的方法
interface Stack {
    void push(Object obj);
    Object pop();
    void undo(); // 把撤销方法纳入统一接口
}

// 基础栈实现
class BasicStack implements Stack {
    // 基础入栈、出栈逻辑...
    @Override
    public void undo() {
        // 默认不支持撤销的话,可抛出异常或留空
        throw new UnsupportedOperationException("不支持撤销操作");
    }
}

// UndoStack装饰器:增强撤销功能
class UndoStack implements Stack {
    private Stack delegate;

    public UndoStack(Stack delegate) {
        this.delegate = delegate;
    }

    @Override
    public void push(Object obj) {
        // 先记录操作,再转发给被装饰对象
        delegate.push(obj);
    }

    @Override
    public Object pop() {
        // 记录操作,再转发
        return delegate.pop();
    }

    @Override
    public void undo() {
        // 执行自己的撤销逻辑,必要时调用delegate的undo
        System.out.println("执行撤销操作");
        delegate.undo();
    }
}

// LockedStack装饰器:增加锁定逻辑
class LockedStack implements Stack {
    private Stack delegate;
    private boolean isLocked = false;

    public LockedStack(Stack delegate) {
        this.delegate = delegate;
    }

    public void lock() {
        isLocked = true;
    }

    public void unlock() {
        isLocked = false;
    }

    @Override
    public void push(Object obj) {
        if (isLocked) {
            throw new IllegalStateException("栈已锁定,无法入栈");
        }
        delegate.push(obj);
    }

    @Override
    public Object pop() {
        if (isLocked) {
            throw new IllegalStateException("栈已锁定,无法出栈");
        }
        return delegate.pop();
    }

    @Override
    public void undo() {
        if (isLocked) {
            throw new IllegalStateException("栈已锁定,无法撤销");
        }
        delegate.undo();
    }
}

这样客户端调用时完全不用管内部的委托对象,直接调用公共方法就行:

Stack myStack = new LockedStack(new UndoStack(new BasicStack()));
myStack.undo(); // 正确的调用方式

最后总结:

  • 你没遗漏任何东西,是教材示例的设计出了问题,它错误地引导你去访问私有成员
  • 装饰器模式的正确用法是通过统一的公共接口调用功能,而非直接操作内部的委托对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 10:40:44