观察者模式中如何限制Observer调用Subject的方法?
解决方案
针对你遇到的问题,核心思路是限制Observer能访问的Subject接口范围,既不破坏Java单继承特性,又能避免Observer调用Subject的管理方法,下面是几种可行方案:
1. 接口隔离原则拆分Subject(最推荐)
把Subject拆分为两个独立接口:一个仅提供Observer需要的数据拉取方法,另一个包含Subject的核心管理方法(注册、通知等)。Observer只依赖数据接口,自然无法调用到管理方法。
代码示例:
// 仅给Observer使用的数据接口,只暴露拉取数据的方法 public interface SubjectDataProvider { // 按需定义Observer需要的数据获取方法 String getCurrentState(); } // 完整的Subject接口,继承数据接口+管理方法 public interface Subject extends SubjectDataProvider { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(); } // Observer仅依赖SubjectDataProvider public interface Observer { void update(SubjectDataProvider dataProvider); } // 具体Subject实现类 public class ConcreteSubject implements Subject { private String state; private List<Observer> observers = new ArrayList<>(); @Override public String getCurrentState() { return state; } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { for (Observer observer : observers) { // 传递的是SubjectDataProvider类型,Observer只能调用数据方法 observer.update(this); } } // 内部状态变更方法 public void setState(String state) { this.state = state; notifyObservers(); } }
2. 代理模式封装Subject
创建一个代理类,仅暴露Observer需要的数据方法,内部持有真实Subject实例。通知Observer时传递代理对象,而非真实Subject。
代码示例:
// 数据接口(同方案1) public interface SubjectDataProvider { String getCurrentState(); } // 完整Subject接口 public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(); String getCurrentState(); } // 代理类,仅实现数据接口 public class SubjectProxy implements SubjectDataProvider { private Subject realSubject; public SubjectProxy(Subject realSubject) { this.realSubject = realSubject; } @Override public String getCurrentState() { return realSubject.getCurrentState(); } } // Observer依赖数据接口 public interface Observer { void update(SubjectDataProvider dataProvider); } // 具体Subject实现类 public class ConcreteSubject implements Subject { private String state; private List<Observer> observers = new ArrayList<>(); @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { SubjectProxy proxy = new SubjectProxy(this); for (Observer observer : observers) { observer.update(proxy); } } @Override public String getCurrentState() { return state; } public void setState(String state) { this.state = state; notifyObservers(); } }
3. 包私有访问控制(场景受限)
如果Subject和Observer都在同一个包下,可以把Subject的notifyObservers()等管理方法设为包私有(即不加访问修饰符),这样包外的Observer无法调用,但同包的Observer仍能调用,适合封闭性较强的项目结构。
内容的提问来源于stack exchange,提问作者Shivam Varshney
相关产品推荐
相关产品推荐

