目录
介绍
观察者模式是一个使用率非常高的模式,它最常用的地方就是GUI系统、订阅-发布系统,因为这个模式的一个重要作用就是解耦,使得它们之间的依赖性更小,甚至作到毫无依赖,以GUI系统来说,应用的UI具有易变性,尤其是前期随着业务的改变或者产品需求的修改,应用界面也会经常发生变化,但是业务逻辑基本变化不大,此时GUI系统需要一套机制来应对这种情况,使得UI层与具体的业务逻辑解耦,观察者模式此时就派上用场了。
定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
使用场景
1、关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合关系;
2、事件多级触发场景;
3、跨系统的消息交换场景,如消息队列、事件总线的处理机制;
代码实现
在我们的日常工作中,产品需求经常发生变化,只要是合理的变更,我们就需要响应,伪代码模拟一下我们码农如下:
public class Coder implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("收到更新通知");
}
}
当我们收到产品的需求变更时,需要及时响应,伪代码模拟的产品如下:
public class Product extends Observable {
public void change() {
setChanged();
notifyObservers();
}
}
产品定义的需求变更决策完成,需要打变量时,就需要通知码农去实现,码农和产品关联的过程如下:
public class Test {
public static void main() {
Product product = new Product();
Coder coder1 = new Coder();
Coder coder2 = new Coder();
Coder coder3 = new Coder();
product.addObserver(coder1);
product.addObserver(coder2);
product.addObserver(coder3);
product.change();
}
}
当前有三个码农在实现这个需求,所以他们一开始会注册到该产品团队中,产品需求变更时,只需要执行product.change(),所有的码农都会收到变更通知了。
Android源码中的也有很多地方使用观察者模式,我们来看看RecyclerView中是如何使用观察者模式的,当我们要给RecyclerView设置数据时,调用setAdapter传入一个RecyclerView.Adapter类型的变量,RecyclerView.Adapter类的源码如下:
public abstract static class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
private boolean mHasStableIds = false;
private StateRestorationPolicy mStateRestorationPolicy = StateRestorationPolicy.ALLOW;
/**
* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
* an item.
* <p>
* This new ViewHolder should be constructed with a new View that can represent the items
* of the given type. You can either create a new View manually or inflate it from an XML
* layout file.
* <p>
* The new ViewHolder will be used to display items of the adapter using
* {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display
* different items in the data set, it is a good idea to cache references to sub views of
* the View to avoid unnecessary {@link View#findViewById(int)} calls.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
* @return A new ViewHolder that holds a View of the given view type.
* @see #getItemViewType(int)
* @see #onBindViewHolder(ViewHolder, int)
*/
@NonNull
public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);
/**
* Returns the total number of items in the data set held by the adapter.
*
* @return The total number of items in this adapter.
*/
public abstract int getItemCount();
/**
* Returns true if this adapter publishes a unique <code>long</code> value that can
* act as a key for the item at a given position in the data set. If that item is relocated
* in the data set, the ID returned for that item should be the same.
*
* @return true if this adapter's items have stable IDs
*/
public final boolean hasStableIds() {
return mHasStableIds;
}
/**
* Called when a view created by this adapter has been detached from its window.
*
* <p>Becoming detached from the window is not necessarily a permanent condition;
* the consumer of an Adapter's views may choose to cache views offscreen while they
* are not visible, attaching and detaching them as appropriate.</p>
*
* @param holder Holder of the view being detached
*/
public void onViewDetachedFromWindow(@NonNull VH holder) {
}
/**
* Returns true if one or more observers are attached to this adapter.
*
* @return true if this adapter has observers
*/
public final boolean hasObservers() {
return mObservable.hasObservers();
}
/**
* Register a new observer to listen for data changes.
*
* <p>The adapter may publish a variety of events describing specific changes.
* Not all adapters may support all change types and some may fall back to a generic
* {@link RecyclerView.AdapterDataObserver#onChanged()
* "something changed"} event if more specific data is not