1. 程式人生 > 其它 >JAVA設計模式之觀察者模式(Observer)

JAVA設計模式之觀察者模式(Observer)

技術標籤:java學習筆記設計模式java多執行緒

觀察者模式

一種行為型模式,當物件間存在一對多的對應關係時,並且有需要將通知傳送給所有的依賴物件,這時可以採用觀察者模式。

  • 優點
    • 1、耦合度低
    • 2、有一套相應的觸發機制
  • 缺點
    • 1、如果一個被觀察者物件有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
    • 2、如果在觀察者和觀察目標之間有迴圈依賴的話,觀察目標會觸發它們之間進行迴圈呼叫,可能導致系統崩潰。

程式碼展示

  • 定義介面
    /**
     *觀察者
     */
    public interface Observer {
    //處理訊息
    public void handle(String message)
    ; } /** * 觀察者模式的主題類 */ public interface Subject { //通知所有的觀察者 public void nodifyObservers(String message); //註冊觀察者 public void attach(Observer ob); }
  • 編寫實現
    /**
     * 觀察者實現
     */
    public class DefaultObserver implements Observer {
        @Override
        public void handle(String message) {
            System.
    out.println(message + ": " + Thread.currentThread().getName()); } } /** * 主題類 */ public class DefaultSubject implements Subject { private List<Observer> observers = new ArrayList<>(); @Override public void nodifyObservers(String message) { observers.forEach
    ((o) -> o.handle(message)); } @Override public void attach(Observer ob) { this.observers.add(ob); } }
  • 程式碼測試
    @Test
    public void test_observer(){
        Subject subject = new DefaultSubject();
    
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
    
        subject.nodifyObservers("observer pattern test");
    }
    
  • 測試結果
    observer pattern test: main
    observer pattern test: main
    observer pattern test: main
    observer pattern test: main
    observer pattern test: main
    
  • 改進措施
    以上的notifyObservers方法通知所有的觀察者時,採用的同步的方式處理的,上文已說到,此種同步方式可能會導致系統性能問題,或者有一個出現問題時,會導致其他的觀察者通知不到。那麼,我們做如下改造:
    • Code
    /**
     * 非同步處理主題類
     */
    public class AsyncSubject implements Subject {
    
        private List<Observer> observers = new ArrayList<>();
    
        ExecutorService service = Executors.newFixedThreadPool(10);
    
        @Override
        public void nodifyObservers(String message) {
    //        for (Observer ob : observers) {
    //            service.submit(new Runnable() {
    //                @Override
    //                public void run() {
    //                    ob.handle(message);
    //                }
    //            });
    //        }
    
            observers.forEach((ob) ->{service.submit(() -> ob.handle(message));});
        }
    
        @Override
        public void attach(Observer ob) {
            this.observers.add(ob);
        }
    }
    
    • 測試Code
    @Test
    public void test_observer(){
        Subject subject = new AsyncSubject();
    
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
        subject.attach(new DefaultObserver());
    
        subject.nodifyObservers("observer pattern test");
    }
    
    • 測試結果
    observer pattern test: pool-1-thread-1
    observer pattern test: pool-1-thread-2
    observer pattern test: pool-1-thread-3
    observer pattern test: pool-1-thread-4
    observer pattern test: pool-1-thread-5
    

通過引入執行緒池的方式來解決同步中可能存在的問題,Spring中的多播器也是一樣的原理,有興趣的同學,可以研究研究。