Лучший способ уведомить наблюдателей в MVC? - PullRequest
3 голосов
/ 07 августа 2009

Скажем, у вас есть 5 или 6 переменных в модели, которая интересует определенный вид, вы пишете разные функции для каждой, например

int a;
int b;
int c;

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

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

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

Или у вас есть только один метод уведомления и вы тратите немного процессорного времени

т.е. вместо notifyAObservers и notifyBObservers у вас просто есть notifyObservers

Ответы [ 2 ]

6 голосов
/ 07 августа 2009

Я считаю, что традиционный подход состоит в том, чтобы уведомить всех наблюдателей и позволить им справиться с этим. Это потому, что вы не знаете, какие наблюдатели наблюдают за какой переменной (ами) - вы просто знаете, что они хотят получать уведомления, когда что-то меняется. Однако, если вы знаете, какие наблюдатели наблюдают за какими переменными, а производительность имеет решающее значение, вы можете сделать что-то похожее на то, что у вас есть.

В традиционном шаблоне Observer наблюдатели реализуют метод update (), который вызывается контроллером при изменении. Observables (модель данных) будет иметь метод notifyObservers (), который перебирает Observers и вызывает их метод update (). Затем наблюдатели получают все, что им нужно, и представление обновляется.

Каждый раз, когда я внедряю шаблон Observer, я просто сохраняю список наблюдателей и уведомляю их всех. Таким образом, у меня есть только один список наблюдателей, и остальная часть класса, а также разные наблюдатели могут измениться без внесения каких-либо изменений в заметное уведомление класса.

0 голосов
/ 02 марта 2011

РЕДАКТИРОВАТЬ: я написал свой ответ несколько лет назад. Прочитав это только сейчас, я почувствовал, что мне нужно обновить его.

Я полагаю, что лучший подход - это уведомить всех наблюдателей и позволить взглядам решить, нужно ли им обновляться.

Каждое представление сможет проверить состояние модели и действовать соответственно. Кроме того, «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());
        }
    }
}

Представление просто проверяет тип получаемой наблюдаемой. Однако, если модель имеет много атрибутов и запускает представление для множества различных сценариев, эта простая проверка может обновлять представление слишком часто.

Другой подход будет следующим:

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 "value" не будет уведомлено другой моделью (и приведение не будет выполнено во время выполнения).

Мой личный фаворит - что-то вроде этого:

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);
    }
}

Здесь уведомление отправляет строго типизированный квалификатор, который привязан к модели. Представление может использовать уведомление для извлечения строго типизированной модели (вместо приведения).

Это где-то между наблюдателем и шиной событий.

...