Observable pattern applied in massive record update

I’m trying to apply Observer pattern to a class that contains a set of records.

In Java pseudo code my class is:

public class MyClass<E> extends Observable
{
    private ArrayList<E> items = new ArrayList<E>();

    public MyClass()
    {
    }

    public void add(E e)
    {
        this.items.add(e);

        setChanged();
        notifyObservers();
    }

    public void remove(E e)
    {
        if(this.items.remove(e))
        {
            setChanged();
            notifyObservers();
        }
    }

    ...
}

My problem is: in some cases during program execution I have to do massive deletes and inserts of records in the structure and, for performances purposes, I would like that observer objects are notified only once at end of the whole operation.

Of course I can add some flag variables for handling the calls to setChanged and notifyObservers, but I wonder what is the “best” way to handle this kind of problem.

So my question: What is the best way to design the code to notify observer objects only once after a massive modification of the observed object?

Answer

I think you have 2 general options

  • let the client code explicitly disable notifications
  • encapsulate a change in an own class and use a template method

Let’s take a look at both options. I will use a simple Observer for my examples.

public class StdoutObserver implements Observer {
  @Override
  public void update(Observable o, Object arg) {
    System.out.println("Observable changed: " + o);
  }
}

Client code explicitly disables notifications

public class MyClass<E> extends Observable {
  private ArrayList<E> items = new ArrayList<E>();

  private boolean changing;

  public void setIsChanging(boolean changing){
    this.changing = changing;
    if(!changing && hasChanged()){
      notifyObservers();
    }
  }

  public void add(E e) {
    this.items.add(e);
    notifyChanged();
  }

  public void remove(E e) {
    if (this.items.remove(e)) {
      notifyChanged();
    }
  }

  private void notifyChanged(){
    setChanged();
    if(!changing){
      notifyObservers();
    }
  }
}

and the client code looks like this

MyClass<String> stringMyClass = new MyClass<String>();
stringMyClass.addObserver(new StdoutObserver());

System.out.println("setting changing: true");
stringMyClass.setIsChanging(true);

stringMyClass.add("C");
stringMyClass.add("D");
stringMyClass.add("E");

System.out.println("setting changing: false");
stringMyClass.setIsChanging(false);

Output will be

setting changing: true
setting changing: false
Observable changed: [email protected]

The problem with this solution is that the client code might forget to enable notifications (or tell the observable that the changes are done). In this case the notifications might be turned off forever.

Encapsulate a change in an own class and use a template method

Define an interface to represent the change

public interface ObservableChange<T extends Observable> {
    public void doChange(T observable); 
}

your Observable will then use a template method to ensure that the changing state is resetted when the change is done.

public class MyClass<E> extends Observable {

  private ArrayList<E> items = new ArrayList<E>();

  private boolean changing;

  public void update(ObservableChange<MyClass2<E>> observableChange) {
    setIsChanging(true);
    try {
      observableChange.doChange(this);
    } finally {
      setIsChanging(false);
    }

  }

  private void setIsChanging(boolean changing) {
    this.changing = changing;
    if (!changing && hasChanged()) {
      notifyObservers();
    }
  }

  public void add(E e) {
    this.items.add(e);
    notifyChanged();
  }

  public void remove(E e) {
    if (this.items.remove(e)) {
      notifyChanged();
    }
  }

  private void notifyChanged() {
    setChanged();
    if (!changing) {
      notifyObservers();
    }
  }
}

The client code will then look like this;

MyClass<String> stringMyClass = new MyClass<String>();
stringMyClass.addObserver(new StdoutObserver());


stringMyClass.update(new ObservableChange<MyClass<String>>() {
  @Override
  public void doChange(MyClass<String> observable) {
    observable.add("A");
    observable.add("B");
    observable.add("C");
    observable.add("D");
  }
});

and the output will be

Observable changed: [email protected]

Using a template method ensures that the notifications are only disabled as long as the changes are done, because the observer controls this.

Leave a Reply

Your email address will not be published. Required fields are marked *