JAVA設計模式之觀察者模式

觀察者模式介紹

觀察者模式又被叫做發佈訂閱模式。觀察者模式在Java中非常的常見,比如說Spring中的事件監聽設計就是觀察者模式,再比如說Redis、kafka的發佈訂閱功能就是觀察者模式。

應用場景

觀察者模式在應用上非常廣泛,比如訂閱推送,發佈訂閱功能,聊天場景,微信公衆號訂閱等非常多。這個模式說白了就是:被觀察者(發佈者)生產內容,觀察者(訂閱者)獲取內容。比如說訂閱推送,假如我的博客發了一篇新的文章,那麼那些關注我的人就會收到推送的消息。再比如說51CTO的付費專欄,如果專欄作者發佈了新的專欄內容,那麼那些訂閱了該作者該專欄的人就會收到專欄推送的消息。而聊天分爲一對一和一對多,一對一是私聊模式,而一對多是羣聊模式,他們都是觀察者模式。

觀察者模式類圖

JAVA設計模式之觀察者模式

實現訂閱專欄功能

1.Observer接口

/**
 * @ClassName Observer
 * @Description TODO:描述該接口職責
 * @Author ckmike
 * @Date 18-12-7 下午3:00
 * @Version 1.0
 * @Copyright ckmike
 **/
public interface Observer {
    void update(String message);
}

2.Observerable接口

/**
 * @ClassName Observerable
 * @Description TODO:描述該接口職責
 * @Author ckmike
 * @Date 18-12-7 下午2:56
 * @Version 1.0
 * @Copyright ckmike
 **/
public interface Observerable {

    // 註冊觀察者
    void register(Observer observer);

    // 註銷觀察者
    void remove(Observer observer);

    void notifyObserver();
}

3.SubscriptionChannel類

/**
 * SubscriptionChannel 簡要描述
 * <p> TODO:描述該類職責 </p>
 *
 * @author ckmike
 * @version 1.0
 * @date 18-12-7 下午3:04
 * @copyright ckmike
 **/
public class SubscriptionChannel implements Observerable{

    List<Observer> observers;
    private String message;

    public SubscriptionChannel() {
        this.observers = new ArrayList<Observer>();
    }

    @Override
    public void register(Observer observer) {
        this.observers.add(observer);
    }

    @Override
    public void remove(Observer observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObserver() {
        // 通知所有observer
        for(Observer observer: this.observers){
            observer.update(message);
        }
    }

    public void sendMessage(String message) {
        this.message = message;
        System.out.println("專欄作者更新專欄文章......");
        // 調用通知所有訂閱者
        notifyObserver();
    }
}

4.User類

/**
 * User 簡要描述
 * <p> TODO:描述該類職責 </p>
 *
 * @author ckmike
 * @version 1.0
 * @date 18-12-7 下午3:13
 * @copyright ckmike
 **/
public class User implements Observer {
    private String name;
    private String message;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        this.message = message;
        // 這裏應該寫到數據庫中的,但我們這裏就直接輸出吧,方便
        read();
    }

    public void read() {
        System.out.println(name+"收到推送消息:"+this.message);
    }
}

5.測試用例

/**
 * Test 簡要描述
 * <p> TODO:描述該類職責 </p>
 *
 * @author ckmike
 * @version 1.0
 * @date 18-12-7 下午3:19
 * @copyright ckmike
 **/
public class Test {

    public static void main(String[] args) {
        // 訂閱專欄
        SubscriptionChannel channel = new SubscriptionChannel();

        // 三個用戶
        Observer user = new User("Mike");
        Observer user1 = new User("William");
        Observer user2 = new User("Crane");

        // 用戶訂閱專欄,開啓一個線程進行訂閱
        new Thread(()->{
            // 假設讀者訂閱付費的間隔是10s
            try {
                channel.register(user);
                TimeUnit.SECONDS.sleep(5);
                channel.register(user1);
                TimeUnit.SECONDS.sleep(5);
                channel.register(user2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 專欄作者線程進行發佈文章,每隔一秒發佈一篇文章
        new Thread(()->{
            int i = 1;
            while (true){
                channel.sendMessage("JAVA設計模式之觀察者模式!-第"+i+"章");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i++;
                if(i>5){
                    break;
                }
            }
        }).start();

        // 中途有用戶退出訂閱專欄,同時有人加入訂閱
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(7);
                channel.remove(user1);
                TimeUnit.SECONDS.sleep(5);
                channel.register(new User("Nill"));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

    }

}

JAVA設計模式之觀察者模式
那麼到這裏我們就實現了訂閱專欄消息推送。是不是很簡單。那麼我這裏再給大家提供兩個思考問題:1.如何讓後來訂閱的讀者能夠收到作者之前發佈的消息呢?2.Spring的事件監聽是如何實現的呢?如果你想到了歡迎在下面留言分析,和大家討論喲。好!打完收工!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章