观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
还是通过Adapter中来举例,我们知道调用了Adapter的notifyDataSetChanged(),那么ListView就会得到刷新,怎么做到的呢?
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
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 class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
}
首先必须调用BaseAdapter的registerDataSetObserver方法注册一个观察者,观察者实际上被放入mObservers集合中,当调用BaseAdapter的notifyDataSetChanged方法通知数据源发生变化,那么通知并调用所有观察者的onChanged方法。
再来看看ListView
public class ListView extends AbsListView {
@Override
public void setAdapter(ListAdapter adapter) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver); //注册观察者,观察mAdapter的数据变化,变化了就得到通知执行onChanged方法
}
//AbsListView的内部类
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();实现了ListView的刷新
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
}
//AdapterView的内部类
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout(); //重新测量,布局,绘制
}
}
}
public class ListView extends AbsListView
public abstract class AbsListView extends AdapterView<ListAdapter>
可以看到最终BaseAdapter的notifyDataSetChanged方法通知数据源发生变化会执行到requestLayout()来实现了ListView的刷新
适配器模式
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
1. 业务的接口与工作的类不兼容,(比如:类中缺少实现接口的某些方法)但又需要两者一起工作
2. 在现有接口和类的基础上为新的业务需求提供接口
适配器模式分为类适配器模式和对象适配器模式。
ListViews做为client,他所需要的目标接口(target interface)就是ListAdapter,包含getCount(),getItem(),getView()等几个基本的方法,为了兼容List,Cursor等数据类型作为数据源,我们专门定义两个适配器来适配他们:ArrayAdapter和CursorAdapter。这两个适配器,说白了,就是针对目标接口对数据源进行兼容修饰。这就是适配器模式。
BaseAdapter跟数据源Cursor和List是不兼容的,现在需要两者一起工作,所以ArrayAdapter和CursorAdapter来适配
public interface Adapter {
int getCount();
}
//BaseAdapter->ListAdapter->Adapter
public abstract class CursorAdapter extends BaseAdapter implements Filterable, CursorFilter.CursorFilterClient{ //类适配
protected Cursor mCursor;
public CursorAdapter(Context context, Cursor c, int flags) { //对象适配
init(context, c, flags);
}
public int getCount() {
if (mDataValid && mCursor != null) {
return mCursor.getCount();
} else {
return 0;
}
}
public Cursor getCursor() { //实现CursorFilterClient接口方法
return mCursor;
}
}
public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter{ //类适配
private List<T> mObjects;
public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
@NonNull List<T> objects) { //对象适配
........
mObjects = objects;
........
}
public int getCount() {
return mObjects.size();
}
@Override
public Resources.Theme getDropDownViewTheme() { //实现ThemedSpinnerAdapter接口方法
return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
}
可以看到其实ArrayAdapter和CursorAdapter既用了类适配也用了对象适配
桥接模式
将抽象部分与实现部分分离,使它们都可以独立的变化。
- 如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系。
- 设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的。
- 需要跨越多个平台的图形和窗口系统上。
- 一个类存在两个独立变化的维度,且两个维度都需要进行扩展。
角色介绍
- 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。 修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
- 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
- 具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。
public interface Adapter {
............
int getCount();
Object getItem(int position);
............
}
public interface ListAdapter extends Adapter{
//继承自Adapter,扩展了自己的两个实现方法
public boolean areAllItemsEnabled();
boolean isEnabled(int position);
}
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
//这里需要一个泛型的Adapter
public abstract T getAdapter();
public abstract void setAdapter(T adapter);
}
public abstract class AbsListView extends AdapterView<ListAdapter>
//继承自AdapterView,并且指明了T为ListAdapter
ListAdapter mAdapter;
//代码省略
//这里实现了setAdapter的方法,实例了对实现化对象的引用
public void setAdapter(ListAdapter adapter) {
//这的adapter是从子类传入上来,也就是listview,拿到了具体实现化的对象
if (adapter != null) {
mAdapterHasStableIds = mAdapter.hasStableIds();
if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds &&
mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Integer>();
}
}
if (mCheckStates != null) {
mCheckStates.clear();
}
if (mCheckedIdStates != null) {
mCheckedIdStates.clear();
}
}
}
抽象化的角色一个视图的集合AdapterView,它扩展了AbsListView,AbsSpinner,接下来他们分别扩展了ListView,GridView,Spinner,Gallery,用不同方式来展现这些ItemViews,我们继续扩展类似ListView的PulltoRefreshView等等。而实现化角色Adapter扩展了ListAdpater,SpinnerAdapter,接着具体的实现化角色BaseAdapter实现了他们,我们通过继承BaseAdapter又实现了我们各式各样的ItemView。
AdapterView和Adapter是两个维度,互不干涉,方便两个类方便进行拓展,AdapterView作为抽象话角色实例了对实现化Adapte对象的引用
总结一下,在ListView中我们看到了三种设计模式,分别是适配器,桥接,观察者模式。注意区分适配器模式和桥接模式,两者完全不一样的。
组合模式
将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
ViewGroup和View的关系就是典型的组合模式,ViewGroup是View的容器,同时也是View的子类,可以对View进行添加删除等操作。同时对ViewGroup组合对象和单个对象View比如获取宽高getWidth()/getHeight()以及其它的操作具有一致性
public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {
public final int getWidth() {
return mRight - mLeft;
}
public final int getHeight() {
return mBottom - mTop;
}
........
}
public abstract class ViewGroup extends View{
public void addView(View child) {
//...
}
public void removeView(View view) {
//...
}
public View getChildAt(int index) {
try {
return mChildren[index];
} catch (IndexOutOfBoundsException ex) {
return null;
}
}
}
public class TextView extends View
public class LinearLayout extends ViewGroup
TextView作为具体的叶子节点对象,LinearLayout作为具体的组合对象,不管是View还是ViewGroup获取宽高都可以通过getWidth()/getHeight()来实现
ViewGroup组合对象的内容(包含的子view)既可以是View也可以是ViewGroup
再比如,文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式。