1、概念
在對象之間定義了一對多的依賴,使得麼當一個對象狀態發生改變,其相關依賴對象會收到通知並自動更新。
2、場景
- 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面
- 一個對象的改變將導致一個或多個其他對象也發生改變
- 需要在系統中創建一個觸發鏈
3、UML結構圖分析
- 抽象被觀察者角色:也就是一個抽象主題,它把所有對觀察者對象的引用保存在一個集合中,每個主題都可以有任意數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者角色。一般用一個抽象類和接口來實現。
- 抽象觀察者角色:爲所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
- 具體被觀察者角色:也就是一個具體的主題,在集體主題的內部狀態改變時,所有登記過的觀察者發出通知。
- 具體觀察者角色:實現抽象觀察者角色所需要的更新接口,一邊使本身的狀態與製圖的狀態相協調。
4、實際代碼分析
實現觀察者代碼:
/**
*
* 創建觀察者抽象類
*/
public interface Observer {
//更新方法
void update(String newStatus);
}
/**
* 創建觀察者實現類
*/
public class ConcreteObserver implements Observer {
/**
* 觀察者狀態
*/
private String observerState;
@Override
public void update(String newStatus) {
observerState = newStatus;
System.out.println(newStatus);
}
}
/**
* 創建抽象目標者
* Created by shidawei on 2019/5/23.
*/
public abstract class Subject {
private List<Observer> mObservers = new ArrayList<>();
/**
* 註冊觀察
* @param observer
*/
public void attach(Observer observer){
mObservers.add(observer);
System.out.println("註冊觀察");
}
/**
* 移除觀察者
* @param observer
*/
public void detach(Observer observer){
mObservers.remove(observer);
}
/**
* 通知觀察者
* @param newStatus
*/
public void notifyObsercers(String newStatus){
for(Observer observer:mObservers){
observer.update(newStatus);
}
}
}
/**
* 實現被觀察者
*/
public class ConcreteSubject extends Subject {
private String state;
public String getState() {
return state;
}
public void change(String newState){
state = newState;
System.out.println(newState);
notifyObsercers(newState);
}
}
//測試代碼
ConcreteSubject concreteSubject = new ConcreteSubject();
concreteSubject.attach(new ConcreteObsercer());
concreteSubject.attach(new ConcreteObsercer());
concreteSubject.attach(new ConcreteObsercer());
concreteSubject.change("123");
java內部的接口實現:
/**
* Observable 是被觀察者對象接口,是對被觀察者的實現
*/
public class TargetObervable extends Observable {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
//被觀察者數據發生改變的時候通過如下兩行代碼通知所有觀察者
this.setChanged();
this.notifyObservers();
}
}
/**
* Observer 對象是觀察者,實現Observer的對象就是實現觀察者對象
*/
public class TargetOberver implements Observer {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name + "收到數據變更" + ((TargetObervable) o).getMessage());
}
}
//測試代碼
TargetObervable targetObervable = new TargetObervable();
targetObervable.addObserver(new TargetOberver());
targetObervable.addObserver(new TargetOberver());
targetObervable.addObserver(new TargetOberver());
targetObervable.setMessage("1234");
兩種觀察者對比:
通過讀源碼Observable.class我們得知對Observer的集合爲Vector
Vector爲線程安全的,會保證線程安全,但是性能差。可以採用CopyOnWriteArrayList來代替Vector。
觀察者設計模式在Android中的實際運用
回調模式:一對一的模式
實現了抽象類/接口的實例實現了負累的提供的抽象方法,然後將該方法還給父類來處理。
Fragment與activity通信的代碼實例:
/**
*回調接口,與activity通信
**/
public interface ISwitchCaoZuoRecordFragment {
void toSwitch(CaiZuoRecordFragFragment fragment, CaiZuoRecordFragPresenter presenterDecorator);
}
/**
* activity實現該接口
**/
public class CaoZuoRecordActivity extends BaseActivity<CaoZuoRecordView, CaoZuoRecordPresenter> implements CaoZuoRecordView ,CaiZuoRecordFragFragment.ISwitchCaoZuoRecordFragment{
@Override
public void toSwitch(CaiZuoRecordFragFragment fragment, CaiZuoRecordFragPresenter presenterDecorator) {
mPresenterDecorator = presenterDecorator;
if(presenterDecorator.studentName!=null&&!presenterDecorator.studentName.equals("")){
searchListTitleBar.getSearch().setText(presenterDecorator.studentName);
searchListTitleBar.getClear().setVisibility(View.VISIBLE);
searchListTitleBar.getSearch_layout().setVisibility(View.VISIBLE);
}else{
searchListTitleBar.getSearch().setText("");
searchListTitleBar.getClear().setVisibility(View.GONE);
searchListTitleBar.getSearch_layout().setVisibility(View.GONE);
}
}
/**
*fragment註冊和取消
*/
@Override
public void onDetach() {
super.onDetach();
iSwitchCaoZuoRecordFragment = null;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof ISwitchCaoZuoRecordFragment) {
iSwitchCaoZuoRecordFragment = (ISwitchCaoZuoRecordFragment) context;
}else{
throw new RuntimeException(context.toString()
+ " 必須實現 ISwitchCaoZuoRecordFragment");
}
}