【问题标题】:Best way to notify observers in MVC?在 MVC 中通知观察者的最佳方式?
【发布时间】:2010-11-17 18:44:42
【问题描述】:

假设你的模型中有 5 或 6 个变量是某个 View 感兴趣的,你是否为每个变量写不同的函数,比如

int a;
int b;
int c;

void setA( newA ) {
   a = newA;
   notifyAObservers();
}

void setB( newB ) {
   b = newB;
   notifyBObservers();
}

void setC( newC ) {
   b = newC;
   notifyCObservers();
}

还是你只有一个 notify 方法,浪费一点 CPU 时间

即而不是 notifyAObservers 和 notifyBObservers,你只有 notifyObservers

【问题讨论】:

    标签: model-view-controller design-patterns


    【解决方案1】:

    我相信traditional approach是通知所有观察者,让他们处理。这是因为您不知道哪些观察者正在观察哪些变量——您只知道他们希望在发生变化时得到通知。但是,如果您确实知道哪些观察者正在观察哪些变量,并且性能至关重要,那么您也许可以做一些与您所拥有的类似的事情。

    在传统的观察者模式中,观察者实现了一个 update() 方法,该方法在发生更改时由控制器调用。 Observables(数据模型)将有一个 notifyObservers() 方法,该方法遍历 Observers 并调用它们的 update() 方法。然后,观察者得到他们需要的任何东西并更新视图。

    然而,每当我实现了观察者模式时,我都会简单地保留一个观察者列表并通知他们。这样,我只有一个观察者列表,并且类的其余部分以及不同的观察者都可以更改,而无需我对可观察类通知进行任何更改。

    【讨论】:

    • 它还使事情变得简单,因为有一些方法可以找出哪些观察者正在观察哪个变量。然而,这最终可能看起来很复杂。
    • 你能给我举个简单的例子吗?我已经投票给你了,但是视图中将实现哪些方法,如何通知它们等等。谢谢!
    • 你的意思是所有的 Observers 都只是实现一个“notify()”方法,然后他们每次都会轮询模型以获取他们感兴趣的数据。例如,notifyObservers() 直接遍历 Observers 列表并调用 notify()。每个观察者从模型中提取它想要的数据并相应地更新它的视图。就像如果变量 A 改变了,B-Observers 仍然会收到一个 notify() 调用,并且会说 b = model.getB() 之类的东西,即使 b 没有改变?
    • 我不确定您在寻找什么 - 我的帖子中的链接包含 Java 和 Python 中的观察者模式示例。您能否详细说明您的任何具体问题?
    • 当我发布我的评论时,您发布了您的第二条评论。但是,是的,你是对的。我也确实将它添加到我的原始帖子中。
    【解决方案2】:

    编辑:几年前我写了我的答案。刚刚看完,觉得有必要更新一下。

    我认为最好的方法是通知所有观察者,让意见决定他们是否需要更新自己..

    每个视图都能够验证模型的状态并采取相应的行动。 此外,“args”可以用作一个标志来指示发生了什么变化(视图可能不希望每一个微小的变化都更新自己)。

    这样,模型真的不知道视图显示的方式和内容,它们是解耦的。

    第一个实现如下所示:

    public class MyModelV1 extends Observable {
        private int value;
        public void setValue(int value) {
            this.value = value;
            setChanged();
            notifyObservers();
        }
        public int getValue() {
            return value;
        }
    }
    public class MyViewV1 implements Observer {
        public void update(Observable o, Object arg) {
            if (o instanceof MyModelV1) {
                System.out.println(((MyModelV1) o).getValue());
            }
        }
    }
    

    视图只是检查接收到的 observable 的类型。 但是,如果模型有很多属性并且会针对很多不同的场景触发视图,那么这种简单的检查可能会过于频繁地刷新视图。

    另一种方法如下:

    public class MyModelV2 extends Observable {
        private int value;
        public void setValue(int value) {
            this.value = value;
            setChanged();
            notifyObservers("value");
        }
        public int getValue() {
            return value;
        }
    }
    public class MyViewV2 implements Observer {
        public void update(Observable o, Object arg) {
            if (o instanceof MyModelV2 && "value".equals(arg)) {
                System.out.println(((MyModelV2) o).getValue());
            }
        }
    }
    

    在这里,通知传递了一个限定符,它让视图更精确地决定何时刷新自己。 视图仍然需要检查和转换模型,因为没有保证 arg“值”没有被另一个模型通知(并且转换会在运行时失败)。

    我个人最喜欢的是这样的:

    public class MyModelV3 extends Observable {
        private int value;
        public void setValue(int value) {
            this.value = value;
            setChanged();
            Notification.MY_MODEL_VALUE_UPDATED.notifyObserver(this);
        }
        public int getValue() {
            return value;
        }
    }
    public class MyViewV3 implements Observer {
        public void update(Observable o, Object arg) {
            if (Notification.MY_MODEL_VALUE_UPDATED.equals(arg)) {
                MyModelV3 model = Notification.MY_MODEL_VALUE_UPDATED.getModel(o);
                System.out.println(model.getValue());
            }
        }
    }
    public class Notification<T extends Observable> {
        public static final Notification<MyModelV3> MY_MODEL_VALUE_UPDATED = new Notification<MyModelV3>();
        private Notification() {
        }
        public T getModel(Observable o) {
            return (T) o;
        }
        public void notifyObserver(T observable){
            observable.notifyObservers(this);
        }
    }
    

    这里,通知发送一个强类型限定符,它绑定到模型。 视图能够使用通知来检索强类型模型(而不是强制转换)。

    这介于观察者和事件总线之间。

    【讨论】:

      猜你喜欢
      • 2018-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-02
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 2010-09-23
      相关资源
      最近更新 更多