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

观察者模式中观察者需不同更新参数的解决方案探讨

观察者模式实现方案分析与优化建议

咱们先逐个拆解你提到的两种实现思路,再聊聊更贴合设计规范的优化方案:

一、现有两种思路的问题分析

1. 按观察者类型判断传参的思路

这种做法直接违背了观察者模式的核心设计初衷——发布者只需要依赖观察者接口,完全不需要知道具体的观察者实现类。

试想一下,以后要是新增一种观察者(比如飞船生产日志记录器),你就必须修改notifyObservers方法,加新的else if分支,这直接违反了开闭原则(对扩展开放、对修改关闭)。而且发布者和具体观察者类耦合死了,后续维护成本会越来越高。

2. 全参数统一update的思路

这种思路虽然满足了“统一update方法”的要求,但缺点也很突出:

  • 参数列表过于臃肿,观察者要接收一堆自己根本用不上的参数,代码可读性极差;
  • 以后要是新增生产相关的参数(比如新增一种资源或飞船类型),所有观察者的update方法都得跟着修改,同样违反开闭原则,也不符合接口隔离原则(观察者不该依赖自己不需要的参数)。

二、更合理的优化方案:用事件对象封装更新数据

核心思路是:把所有更新需要的参数封装成一个事件对象(DTO),让观察者的update方法只接收这个对象,观察者按需从对象里提取自己需要的信息。这样既符合观察者模式规范,又兼顾了扩展性和可读性。

具体实现示例

1. 定义事件类,封装所有生产相关数据

public class ShipProductionEvent {
    // 资源消耗字段
    private int metalRequired;
    private int energyRequired;
    private int carbonRequired;
    private int deuteriumRequired;
    private int vibraniumRequired;
    // 飞船生产数量字段
    private int numberOfLightFighters;
    private int numberOfHeavyFighters;
    private int numberOfStarDestroyers;
    // 可根据需求扩展其他字段

    // 构造器:初始化所有字段
    public ShipProductionEvent(int metalRequired, int energyRequired, int carbonRequired,
                               int deuteriumRequired, int vibraniumRequired,
                               int numberOfLightFighters, int numberOfHeavyFighters,
                               int numberOfStarDestroyers) {
        this.metalRequired = metalRequired;
        this.energyRequired = energyRequired;
        this.carbonRequired = carbonRequired;
        this.deuteriumRequired = deuteriumRequired;
        this.vibraniumRequired = vibraniumRequired;
        this.numberOfLightFighters = numberOfLightFighters;
        this.numberOfHeavyFighters = numberOfHeavyFighters;
        this.numberOfStarDestroyers = numberOfStarDestroyers;
    }

    // 提供getter方法,让观察者获取需要的数据
    public int getMetalRequired() { return metalRequired; }
    public int getEnergyRequired() { return energyRequired; }
    public int getNumberOfLightFighters() { return numberOfLightFighters; }
    // 其他字段的getter...
}

2. 调整观察者接口,让update接收事件对象

public interface Observer {
    void update(ShipProductionEvent event);
}

3. 修改发布者的notifyObservers方法

public class SpaceShipFactory implements Publisher {
    private List<Observer> observers = new ArrayList<>();
    // 工厂自身的状态字段:资源需求、生产的飞船数量等
    private int metalRequired;
    private int energyRequired;
    // ... 其他状态字段

    @Override
    public void notifyObservers() {
        // 创建事件对象,把当前生产的所有数据封装进去
        ShipProductionEvent event = new ShipProductionEvent(
            this.metalRequired, this.energyRequired, this.carbonRequired,
            this.deuteriumRequired, this.vibraniumRequired,
            this.numberOfLightFighters, this.numberOfHeavyFighters,
            this.numberOfStarDestroyers
        );
        // 遍历所有观察者,统一传入事件对象
        for (Observer obs : observers) {
            obs.update(event);
        }
    }

    // 其他方法:添加/移除观察者、生产飞船逻辑等...
}

4. 观察者按需提取数据

  • PlanetResources的update实现:只关注资源消耗相关数据
public class PlanetResources implements Observer {
    private int metallicMicrolattice;
    private int energy;
    private int carbyne;
    private int deuterium;
    private int vibranium;

    @Override
    public void update(ShipProductionEvent event) {
        // 只提取自己需要的资源字段,更新资源存储
        this.metallicMicrolattice -= event.getMetalRequired();
        this.energy -= event.getEnergyRequired();
        this.carbyne -= event.getCarbonRequired();
        this.deuterium -= event.getDeuteriumRequired();
        this.vibranium -= event.getVibraniumRequired();
    }
}
  • StationedShip的update实现:只关注飞船生产数量数据
public class StationedShip implements Observer {
    private ArrayList<SpaceShip> lightFighters;
    private ArrayList<SpaceShip> heavyFighters;
    private ArrayList<SpaceShip> starDestroyers;
    // ... 其他飞船列表

    @Override
    public void update(ShipProductionEvent event) {
        // 提取飞船生产数量,更新飞船存储
        addLightFighters(event.getNumberOfLightFighters());
        addHeavyFighters(event.getNumberOfHeavyFighters());
        addStarDestroyers(event.getNumberOfStarDestroyers());
    }

    // 辅助方法:批量添加飞船到对应列表
    private void addLightFighters(int count) {
        for (int i = 0; i < count; i++) {
            lightFighters.add(new LightFighter());
        }
    }
    // 其他添加飞船的辅助方法...
}

三、这个方案的核心优势

  1. 符合观察者模式规范:发布者只依赖Observer接口,完全不知道具体的观察者实现,彻底解耦;
  2. 扩展性极强:以后新增资源类型、飞船类型,只需要修改ShipProductionEvent类加字段;新增观察者类型,只需要实现Observer接口,完全不需要修改发布者和已有观察者的代码;
  3. 可读性高:观察者的update方法逻辑清晰,只处理自己关心的数据,不会被无用参数干扰;
  4. 维护成本低:所有生产相关的数据都集中在事件类里,修改或新增数据只需要在一个地方操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:58:01