您的位置:首页 > 其它

设计模式(3)-观察者模式

2017-12-27 10:20 162 查看
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

类图

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作



结合BaseAdapter源码理解一下观察者模式

被观察者代码:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//使用对象适配器模式
private final DataSetObservable mDataSetObservable = new DataSetObservable();

public boolean hasStableIds() {
return false;
}
//订阅
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
//移除订阅
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}

//通知附加的观察者,底层的数据已经被改变了
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}

//通知附加的观察者,底层的数据已经失效
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}

public boolean areAllItemsEnabled() {
return true;
}

public boolean isEnabled(int position) {
return true;
}

public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}

public int getItemViewType(int position) {
return 0;
}

public int getViewTypeCount() {
return 1;
}

public boolean isEmpty() {
return getCount() == 0;
}
}


baseAdapter结合了适配器模式+观察者模式一起实现的。

对适配器模式不清楚的可以移步设计模式(2)-适配器模式

观察者代码:

public abstract class DataSetObserver {
//观察者发生变化的操作
public void onChanged() {
// Do nothing
}

//当数据失效对应的操作
public void onInvalidated() {
// Do nothing
}
}


准备集合存放订阅者

public abstract class Observable<T> {
//观察者列表
protected final ArrayList<T> mObservers = new ArrayList<T>();

//订阅
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}

//移除订阅关系
public void unregisterObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
int index = mObservers.indexOf(observer);
if (index == -1) {
throw new IllegalStateException("Observer " + observer + " was not registered.");
}
mObservers.remove(index);
}
}

//移除所有的观察者
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}


接着看下面具体的实现

public class DataSetObservable extends Observable<DataSetObserver> {

//被观察者发型变化时,通知所有的观察者
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}

public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}


下面是适配模式:目标角色(Target)部分代码

public interface Adapter {
//实现订阅
void registerDataSetObserver(DataSetObserver observer);

//移除订阅
void unregisterDataSetObserver(DataSetObserver observer);

int getCount();

Object getItem(int position);

long getItemId(int position);

boolean hasStableIds();

View getView(int position, View convertView, ViewGroup parent);

static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;

int getItemViewType(int position);

int getViewTypeCount();

static final int NO_SELECTION = Integer.MIN_VALUE;

default @Nullable CharSequence[] getAutofillOptions() {
return null;
}
}


优点:

观察者和被观察者是抽象耦合的。

.建立一套触发机制

缺点:

如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景

有多个子类共有的方法,且逻辑相同。

重要的、复杂的方法,可以考虑作为模板方法。

注意事项:

- JAVA 中已经有了对观察者模式的支持类。

- 避免循环引用。

- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息