早就對“設計模式”這個詞有所耳聞,最早是在大一看《大話數據結構》這本書的背后看到這個系列還有個《大話設計模式》,我當時還以為這個“設計模式”恐怕是給設計師看的吧,當然這是望文生義了。其實設計模式官方解釋是:
設計模式(Design Pattern)是一套被反復使用、多數人知曉的、經過分類的、代碼設計經驗的總結。
其實我認為就是大家總結的寫代碼的套路吧。
觀察者模式
觀察者模式從名字上來看大概就是一種通知與被通知的關系,其實代碼思想也與其差不多,其核心思想就是有一個或N個觀察者(Observer)和一個(或N個)被觀察者(Observable 或 Subject),觀察者以訂閱方式來觀察被觀察者,當被觀察者接到更新時(程序員控制或代碼自動發出)將通知所有觀察者來接受更新的內容。這就有點像一群學生(Observer,觀察者)和書店老板(Observable 或 Subject,被觀察者),當書店每次新進漫畫雜志時,就會通知所有學生去購買。下面就看看如何用代碼來實現這個事件。
所需接口
我們需要一共三個接口來定義Observer和Observable的行為,為別是 Observer 和 Observable 本身,還有DisplayElement來定義Observer的輸出動作。
public interface Observable
{
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public interface Observer
{
void update(String book);
}
public interface DisplayElement
{
void display();
}
接口定義的方法都很好理解,Observable 接口定義了將 Observer 對象加入或刪除自己的隊列里,還有通知隊列里的 Observer。當書店有新書進入時,就會調用 Observer 的 update 方法。
實現接口
我們需要的類只有兩個,當然就是 BookStore 對象和 Student 對象。
public class BookStore implements Observable
{
private List<Observer> observers;
private String newBook;
public BookStore()
{
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer)
{
observers.add(observer);
}
@Override
public void removeObserver(Observer observer)
{
observers.remove(observer);
}
@Override
public void notifyObservers()
{
if(newBook!=null)
{
for (Observer observer : observers)
{
observer.update(newBook);
}
}
newBook=null;
}
public void newBookComing(String bookName)
{
newBook = bookName;
notifyObservers();
}
}
public class Student implements DisplayElement , Observer
{
private String name;
private List<String> hasBooks;
private Observable observable;
public Student(String name,Observable observable)
{
this.name = name;
this.hasBooks = new ArrayList<>();
this.observable = observable;
observable.registerObserver(this);
}
@Override
public void update(String book)
{
hasBooks.add(book);
System.out.print(name+"買到了書<"+book+"> ");
display();
}
@Override
public void display()
{
System.out.println(name+"有書->"+hasBooks.toString());
}
}
可以看到 BookStore 就是實現了很簡單的 Observable 類的三個接口,其中在 notifyObservers 方法中依次調用隊列中的 Observer 對象的 update 方法,BookStore 在 newBookComing 方法中設置新書的名字和調用 notifyObservers 方法。而 Student 則是在 update 方法中將新書加入自己已有的書籍集合中,最后調用 display 方法打印目前所有的書名。值得注意的是 Student 對象是把被觀察者在自己的構造函數里傳入,然后在構造函數里調用被觀察者(這里就是 BookStore)的 registerObserver 方法將自己加入到隊列中去。我認為當然也可以不這么做,也可以 bookStore.registerObserver(xiaohua);
來加入BookStore的隊列,RxJava就是這么做的。
測試
現在建立一個測試類來跑一跑我們的代碼:
public class Main
{
public static void main(String[] args)
{
BookStore bookStore = new BookStore();
Student xiaoming = new Student("小明", bookStore);
Student xiaohua = new Student("小華", bookStore);
Student xiaozhang = new Student("小張", bookStore);
bookStore.newBookComing("知音漫客");
bookStore.newBookComing("故事會");
bookStore.newBookComing("看天下");
}
}
那么我們僅僅用了這么幾行代碼就跑出了我們想要的結果:
小明買到了書<知音漫客> 小明有書->[知音漫客]
小華買到了書<知音漫客> 小華有書->[知音漫客]
小張買到了書<知音漫客> 小張有書->[知音漫客]
小明買到了書<故事會> 小明有書->[知音漫客, 故事會]
小華買到了書<故事會> 小華有書->[知音漫客, 故事會]
小張買到了書<故事會> 小張有書->[知音漫客, 故事會]
小明買到了書<看天下> 小明有書->[知音漫客, 故事會, 看天下]
小華買到了書<看天下> 小華有書->[知音漫客, 故事會, 看天下]
小張買到了書<看天下> 小張有書->[知音漫客, 故事會, 看天下]
總結
如果以后有新書來的話,只需要一行代碼 bookStore.newBookComing("知音漫客");
就可以完成所有的通知動作了。觀察者模式將變化的部分與固定的部分分開從而實現了松耦合,這就是觀察者模式的威力。java 在自己的 util 包里也內置了一個觀察者模式,他的類名與我寫的代碼的類名是一樣的,有所不同的是內置的 Observable 是一個類而不是一個接口,因為他幫我們把 registerObserver ,removeObserver ,notifyObservers 都實現了,其余的使用方法都大同小異。