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

观察者模式中如何限制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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:05:15