2013-10-05 53 views
4

我对java非常陌生,所以我提前抱歉,如果有什么我说听起来新鲜,温柔。Java观察者模式 - 如何在更新(通知)循环/迭代期间删除观察者?

我已经实现了一个基本的观察者模式。一些观察者应该只听一个更新,然后立即从观察者/听众列表中删除自己。但是,每当我尝试这样做时,我都会遇到着名的java.util.concurrentmodificationexception错误。

我很明显得到这个错误,因为我在改变列表的同时还在迭代它,但我仍然不确定什么是正确的解决方案。我想知道我是否以正确的方式做这件事。如果我是,那么需要什么修复才能使它工作?如果我不是,我希望得到更好的方法来实现我想要做的事情。

这里是我的代码:

public interface Listener { 
    public void onValueChange(double newValue); 
} 


public class Observed { 
    private int value; 
    List<Listener> listeners = new ArrayList<>(); 

    public void addListener(Listener toAdd) { 
     listeners.add(toAdd); 
    } 

    public void removeListener(Listener toRemove) { 
     listeners.remove(toRemove); 
    } 

    public void changeValue(double newValue) { 
     value = newValue; 
     for (Listener l : listeners) l.onValueChange(newValue);        
    } 
} 


public class SomeClassA implements Listener{ 
    private Observed observed; 

    SomeClassA(Observed observed) { 
     this.observed = observed; 
    } 

    @Override 
    public void onValueChange(double newValue) { 
     System.out.println(newValue); 
     observed.removeListener(this); 
    } 
} 


public class SomeClassB implements Listener{ 
    @Override 
    public void onValueChange(double newValue) { 
     System.out.println(newValue); 
    } 
} 



public class ObserverTest { 
    public static void main(String[] args) { 
     Observed observed = new Observed(); 
     SomeClassA objectA = new SomeClassA(observed); 
     SomeClassB objectB = new SomeClassB(); 

     observed.addListener(objectB); 
     observed.addListener(objectA); 

     observed.changeValue(4); 
    } 
} 
+0

缺少在'value =(int)double之前强制转换;' – herry

回答

5

一个办法是去FO CopyOnWriteArraylist,而不是ArrayList中。

的CopyOnWriteArrayList是ArrayList的一个线程安全的变体,其中所有 可变操作(添加,设置,等等)由 实现对底层数组的一个新的副本。

原因为什么它在你的情况下抛出

您直接修改集合,而它是根据法changeValue()遍历集合

+0

谢谢。更正它。 –

1

你不能从一个集合,同时删除项目你正在迭代它。也就是说,除非您使用Iterator#remove方法。由于在这种情况下这不是一种可能性,所以另一种方法是制作监听器列表的副本,然后对其进行迭代。在这种情况下,原来的听众列表是免费的由个别的收听进行操作:

public void changeValue(double newValue) { 
    value = newValue; 
    List<Listener> copyOfListeners = new ArrayList<Listener>(listeners); 
    for(Listener l : copyOfListeners) { 
     l.onValueChange(newValue); 
    } 
} 
+2

而不是在每次迭代中进行复制,在列表的每次修改(通常更少见)上复制副本可能更便宜,幸运的是,已经有M Sach的答案中的“CopyOnWriteArrayList”你没有进一步的努力。 –

0

以下作品的代码,所以你可以尝试任何它。

import java.util.Observable; 
import java.util.Observer; 
class Model extends Observable { 
    public void setX(double x) { 
     this.x=x; 
     System.out.println("setting x to "+x); 
     setChanged(); 
     notifyObservers(); 
    } 
    double x; 
} 
class A implements Observer { 
    A(Model model) { 
     this.model=model; 
    } 
    @Override public void update(Observable arg0,Object arg1) { 
     System.out.println(getClass().getName()+" "+((Model)arg0).x); 
     ((Model)arg0).deleteObserver(this); 
    } 
    Model model; 
} 
class B implements Observer { 
    @Override public void update(Observable arg0,Object arg1) { 
     System.out.println(getClass().getName()+" "+((Model)arg0).x); 
    } 
} 
public class So19197579 { 
    public static void main(String[] arguments) { 
     Model model=new Model(); 
     model.addObserver(new A(model)); 
     model.addObserver(new B()); 
     model.setX(4); 
     model.setX(8); 
    } 
}