觀察者模式
觀察者模式是使用率非常高的一種設計模式。
什麼是觀察模式?
對象間存在一對多的依賴關係,需要在某個對象改變的時候,依賴於該對象的所有其他對象都收到通知並進行更新和相應的業務操作。
簡而言之,就是當一個被觀察的對象改變了就要去通知它的觀察者,告訴觀察者我有變化了,你可以進行你需要的處理操作。
無處不在的觀察者
情景一:小明(觀察者)給媽媽說飯熟了叫我吃飯,媽媽(被觀察者)等到飯熟了就會通知小明來吃飯了。
情景二:代碼中有個需求需要監聽用戶打開藍牙就關掉藍牙。這肯定需要使用觀察者模式,監聽到藍牙打開了,就通知相應的觀察者,然後做關掉藍牙的操作。
觀察者模式的作用就是使對象解耦,將觀察者和被觀察者完全隔離。上述情景,小明可以在媽媽做飯的時候寫作業,等媽媽叫她吃飯的時候再去吃飯。這樣小明和媽媽就可以各幹各的事情,完全解耦。
最簡單的觀察者模式Demo
項目結構如下,只有4個類超級簡單。
- 被觀察接口,三個方法,註冊監聽者,註銷監聽者,通知所有觀察者
/**
* 被觀察者接口
*/
public interface IObservable {
void registerObserver(IObserver observer);
void unregisterObserver(IObserver observer);
void notifyAllObservers();
}
- 觀察者接口:更新數據
/**
* 觀察者接口
*/
public interface IObserver {
void update();
}
- 觀察者實現類
/**
* 觀察者實現類
*/
public class ObserverImpl implements IObserver{
private static final String TAG = "ObserverImpl";
private String observerName;
public ObserverImpl(String observerName){
this.observerName = observerName;
}
@Override
public void update() {
Log.i(TAG,observerName +"數據更新了----->");
}
}
- 被觀察者實現類
/**
* 被觀察者實現類
*/
public class ObservableImpl implements IObservable{
private List<IObserver> mObserversList = new ArrayList<>();//註冊的所有觀察者集合
@Override
public void registerObserver(IObserver observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObserversList) {
if (mObserversList.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObserversList.add(observer);
}
}
@Override
public void unregisterObserver(IObserver observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(observer) {
int index = mObserversList.indexOf(observer);
if (index == -1) {
throw new IllegalStateException("Observer " + observer + " was not registered.");
}
mObserversList.remove(index);
}
}
@Override
public void notifyAllObservers() {
for(int i = 0;i < mObserversList.size(); i++){
IObserver observer = mObserversList.get(i);
observer.update();
}
}
}
其實看了被觀察者的實現,原來所謂的註冊監聽和取消監聽都是靠一個list集合來維護,最後的通知觀察者的本質也就是遍歷這個list集合,然後調用觀察者的update方法。
- 測試demo
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ObserverImpl observer1 = new ObserverImpl("觀察者 1 :");
ObserverImpl observer2 = new ObserverImpl("觀察者 2 :");
ObservableImpl observable = new ObservableImpl();//被觀察者
observable.registerObserver(observer1);
observable.registerObserver(observer2);
// observable.unregisterObserver(observer2);
observable.notifyAllObservers();
}
}
- 測試結果:
我們可以從結果看出註冊的2個觀察者都收到數據更新的消息了。這就是目前演示的最簡單的觀察者模式的寫法。
觀察者模式在Android源碼中的使用:
- 四大組件其中一個:Broadcast其實就是一個訂閱發佈的觀察者模式。我們註冊廣播接收者registerReceiver,當sendBroadcast的發送廣播時,onReceive 方法就會被調用。這是一個非常典型的觀察者模式。onReceive方法就類似於上述例子中的觀察者接口中的update()方法。細細想來,其實我們見過的很多代碼其實使用的就是觀察者模式。
-其實ListView使用Adapter模式也是觀察者模式
我們在使用ListView的時候會使用到一個方法notifyDataSetChanged();每當有數據源更新,調用該方法就可以更新頁面。notifyDataSetChanged()源碼其實和上述的被觀察者實現類裏面 notifyAllObservers()的方法類似。
Android源碼其實就是一個很好的學習的例子,我們平時使用的很多模式在源碼中都有體現。觀察者模式是我們必現要掌握的設計模式之一。