装饰器模式扩展功能问题:如何调用LockedStack对象的undo方法?
装饰器模式示例的问题分析
这个教材示例的设计确实有问题,或者说它没正确体现装饰器模式的核心原则。
装饰器模式的核心逻辑是:
- 装饰器和被装饰对象要实现同一个接口(或继承同一抽象类)
- 所有功能调用都得通过装饰器的公共方法转发,绝对不能直接去访问内部的
delegate私有成员
你遇到的问题根源很明确:
- 示例违反了封装原则——私有成员本来就是给内部用的,让客户端直接依赖它完全是错误设计
- 正确的做法应该是:如果
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
相关产品推荐
相关产品推荐

