Android设计模式详解之观察者模式

前言

观察者常用于订阅-发布系统,能够将观察者和被观察者进行解耦,降低两者之间的依赖;

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

使用场景:

  • 关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合关系;
  • 事件多级触发场景;
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。

UML类图:
观察者模式UML

  • Subject:抽象主题,被观察者的角色,抽象主题角色把所有观察者对象的引用保存到一个集合中,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察对象;
  • ConcreteSubject:具体主题,具体被观察者,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知;
  • Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己;
  • ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态发生变化时更新自己的状态;

实现示例

这里以关注微信公众号进行举例,对于公众号是被观察者,对于微信用户则是观察者,微信用户订阅微信公众号后,公众号发布文章通知到微信用户,典型的发布-订阅模式;下面我们就用观察者模式来实现:

  • 定义抽象观察者,Observer
interface Observer<T> {
    //定义文章更新方法
    fun update(t: T)
}
  • 定义抽象被观察者,持有所有的观察者,Observable
open class Observable<T> {
    private val observers = arrayListOf<Observer<T>>()

    /**
     * 订阅被观察者
     */
    fun addObserver(observer: Observer<T>) {
        observers.add(observer)
    }

    /**
     * 解除订阅
     */
    fun removeObserver(observer: Observer<T>) {
        observers.remove(observer)
    }

    /**
     * 通知所有的观察者
     */
    fun notifyObservers(t: T) {
        for (observer in observers) {
            observer.update(t)
        }
    }
}
  • 具体观察者,微信用户,WXUser
class WXUser(private val name: String) : Observer<String> {

    override fun update(article: String) {
        println("$name receive article:$article")
    }

}
  • 微信公众号,具体的被观察者,WXPublicObservable
class WXPublicObservable : Observable<String>() {
    /**
     * 更新公众号文章
     */
    fun updateArticle(article: String) {
        notifyObservers(article)
    }

}
  • 编写测试类以及测试结果
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //定义微信用户
        val user1 = WXUser("user1")
        val user2 = WXUser("user2")
        val wxPublicObservable = WXPublicObservable()
        //订阅公账号
        wxPublicObservable.addObserver(user1)
        wxPublicObservable.addObserver(user2)
        //发布一篇文章
        wxPublicObservable.updateArticle("互联网行业,迎来寒冬...")
        println("---------------------------")
        println("---------------------------")
        //user1取消订阅
        wxPublicObservable.removeObserver(user1)
        wxPublicObservable.updateArticle("疫情何时才能结束...")
    }
}
user1 receive article:互联网行业,迎来寒冬...
user2 receive article:互联网行业,迎来寒冬...
---------------------------
---------------------------
user2 receive article:疫情何时才能结束...

Android源码中的观察者模式

  • ListView中的观察者模式;
    我们首先看下ListView.setAdapter方法
    public void setAdapter(ListAdapter adapter) {
    	//判断是否之前已经注册过观察者,如果注册过先注销,避免多次注册;
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

     ...
        super.setAdapter(adapter);
        if (mAdapter != null) {
        	//创建一个数据集观察者进行注册
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
         ...

        requestLayout();
    }

我们紧着看下AdapterDataSetObserver

    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }

AdapterDataSetObserver会继承DataSetObserver,我们看下DataSetObserver,典型的一个抽象观察者角色

public abstract class DataSetObserver {
    public void onChanged() {
      
    }
    public void onInvalidated() {
      
    }
}

通过上面的ListView.setAdapter方法,就完成了观察者注册工作,我们在看下数据更新时,我们一般会调用notifyDataSetChanged方法

    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();
    }

mDataSetObservable代码如下,显然,调用notifyDataSetChanged方法实际上就是让被观察者去通知观察者数据发生了变化;

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();
            }
        }
    }
}

我们在回头看下AdapterDataSetObserver的onChanged()方法都做了什么

 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged(); //重点看下 super.onChanged()方法
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }

super.onChanged()对应AdapterDataSetObserver.onChanged()方法

    class AdapterDataSetObserver extends DataSetObserver {

     

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            //最终会通过 requestLayout()完成listview所有数据更新
            requestLayout();
        }

小结:Listview数据更新是典型的观察者设计模式,在setAdapter方法里完成了观察者的注册工作,当调用notifyDataSetChanged方法的时候最终会通过requestLayout()完成所有数据更新!

总结

优点:

  • 观察者和被观察者之间是抽象耦合,应对业务变化;
  • 增强系统灵活性、可扩展性;

缺点:
程序中包括一个被观察者,多个观察者对象,消息通知是遍历执行的,一个观察者卡顿,会影响整体的执行效率,这时候可以考虑采用异步的方式。

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Builder设计模式是一种创建型设计模式,它用于创建复杂对象,将对象的构建过程与其表示分离。该设计模式使用一个独立的Builder类来构建对象,而不需要直接使用对象的构造函数。 使用Builder设计模式可以将对象的构建逻辑集中在一个地方,使得代码更加清晰和可读,并且便于维护和扩展。它主要包含以下几个角色: 1. Product(产品):产品类是要创建的复杂对象。它包含多个属性,以及对属性赋值的方法。 2. Builder(抽象建造者):Builder类是一个接口或抽象类,定义了构建产品的方法,包括设置产品的属性以及返回构建好的产品。 3. ConcreteBuilder(具体建造者):ConcreteBuilder类实现了Builder接口,实现了构建产品的具体逻辑,包括设置产品的各个属性,并返回构建好的产品。 4. Director(指挥者):Director类是一个调用者,它负责调用具体建造者来构建产品。它将具体建造者和产品分离,只通过接口或抽象类与它们交互。 使用Builder设计模式的典型步骤如下: 1. 创建产品类,定义产品的属性和方法。 2. 创建抽象建造者接口或抽象类,定义构建产品的方法。 3. 创建具体建造者类,实现抽象建造者接口或抽象类,在其中定义具体的产品构建逻辑。 4. 创建指挥者类,负责调用具体建造者来构建产品。 通过以上步骤,我们可以通过调用指挥者的构建方法,来获取构建好的产品对象。使用Builder设计模式,我们可以将产品的构建过程与表示分离,使得产品构建的灵活性和可扩展性增强。同时,也可以降低客户端使用产品构建过程的复杂性,使得客户端的代码更加简洁和易于维护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值