2013-10-05 92 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); 
    } 
}