java - 可观察模式应用于海量记录更新

标签 java design-patterns observer-pattern

我正在尝试将观察者模式应用于包含一组记录的类。

在 Java 伪代码中,我的类是:

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

    ...
}

我的问题是:在某些情况下,在程序执行期间,我必须在结构中进行大量删除和插入记录,并且出于性能目的,我希望观察者对象仅在整个操作结束时收到一次通知。

当然,我可以添加一些标志变量来处理对 setChangednotifyObservers 的调用,但我想知道处理此类问题的“最佳”方法是什么.

所以我的问题:设计代码的最佳方法是什么,以便在对观察对象进行大规模修改后仅通知观察者对象一次?

最佳答案

我认为你有两个一般选择

  • 让客户端代码显式禁用通知
  • 将更改封装在自己的类中并使用模板方法

让我们看一下这两个选项。我将在示例中使用一个简单的Observer

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

客户端代码显式禁用通知

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

客户端代码如下所示

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

输出将是

setting changing: true
setting changing: false
Observable changed: MyClass@229ed927

此解决方案的问题是客户端代码可能会忘记启用通知(或告诉可观察对象更改已完成)。在这种情况下,通知可能会永远关闭。

将更改封装在自己的类中并使用模板方法

定义一个接口(interface)来表示更改

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

然后,您的Observable将使用模板方法来确保更改完成后重置更改状态。

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

客户端代码将如下所示;

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

输出将是

Observable changed: MyClass2@33837697

使用模板方法可确保仅在更改完成后才禁用通知,因为观察者对此进行控制。

关于java - 可观察模式应用于海量记录更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37807102/

相关文章:

java - org.xml.sax.SAXParseException : Unexpected token while parsing XML

ios - 设计 UITableView/Cell - iOS

node.js - 编写大量类似函数/流程的最佳实践

javascript - 自定义事件(观察者模式)

java - 如何避免观察者模式的循环引用?

java - 在 Java 中转换字符

Java:监听器子类不会更改父类(super class)按钮

java - 使用java仅显示图像的一部分

language-agnostic - 为每个类创建一个 NullObject 是否可行? (当然有工具)

oop - 观察者模式的反面是什么?