写作缘由:对于一个有逼格的程序猿,23种设计模式应该不在话下,为了挤身逼格程序猿之列,决定系统的学习设计模式
关于设计模式(主要是思想方面)
001.定义:
是一套反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
002.目的:
为了可重用代码、让代码更容易被他人理解、保证代码可靠性
设计模式之观察者模式:
定义:定义了对象之间的一种一对多的关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新(其实就是1对n,当“1”发生变化时,“n”全部得到通知,并更新)
应用场景:
小区住户预订牛奶,只要你预定了牛奶,他就会在每天早上7:30送到你家楼下
微信关注的公众号,只要订阅了公众号,当公众号内容发生类变化,订阅过的人们都会得到更新的内容
订阅天气预报,每天都会有更新提醒你最新的天气情况
...
Android中的应用场景:
ListView的适配器,有个函数notifyDataSetChanged()
函数,这个函数其实就是通知ListView的每个Item,数据源发生了变化,请各位Item重新刷新一下
Eventbus的应用,详细就不说了,可自行查阅,这个库是对观察者模式很好的应用
...
下面开始观察者模式学习:
1).认识观察者模式:6大方面
001.目标与观察者之间的关系:
a.观察者与目标对象是一对一关系
b.一个目标对应多个观察者
c .一个观察者对应多个目标(这种情况下,建议观察者对不同观察目标定义不同的回调,还可以在update方法内部区别不同的目标对象)
002.单向依赖:
观察者依赖目标对象,只有目标对象知道什么时候通知观察者,观察者被动的等待通知并执行更新
003.命名的建议:
a.目标接口的定义,建议在名称后面跟上subject
b. 观察者接口的定义,建议在名称后面跟上Observer
c.观察者接口的更新方法,建议名称为update
004.触发通知的时机:完成状态维护之后触发(数据设置完成之后)
005.观察者模式调用示意图:
准备阶段:
运行阶段:
006.通知顺序:
当目标状态改变时,通知各个观察者顺序不确定,所以各个观察者之间不应该有先后依赖关系
2).观察者模式的实现方式:
推模型:不管观察者是否需要,类似有广播通信
目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据
拉模型:
目标对象在通知观察者的时候,只传递少量信息
如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉取数据
一般这种模型的实现中,会把目标对象的自身通过update方法传递给观察者
两种模型的比较:
推模型是假定目标对象知道观察者的数据
拉模型是目标对象不知道观察者具体需要什么数据,因此把自身传递给观察者,由观察者来取值
推模型会使观察者对象难以复用
拉模型下,update方法的参数是目标对象本身,基本上可以适应各种情况的需要
3).观察者的优点:
观察者模式实现了观察者和目标之间的抽象耦合
观察者模式实现了动态联动
观察者模式支持广播通信
4).可能引起无谓的操作(需要在具体场景做以处理)
5).何时使用观察者模式:
a.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
b.如果在更改一个对象的时候,需要同时连带改动其他的对象,而且不知道究竟应该有多少对象需要被连带改变
c.当一个对象必须通知其他的对象,但是你又不希望这个对象和其他被它通知的对象是松散耦合的
放大招的时候到了------->>>上代码
案例情景还原:黄明为她女朋友和丈母娘提供天气预报的订阅,并给她们不同信息回馈
目标对象:
/** * 目标对象:它知道观察者它的观察者,并提供注册(添加)和删除观察者的接口 * (具体的目标类来继承实) */ public class WeatherSubject { //需要一个集合维护观察者的列表:用来保存注册的观察者对象 private List<Observer> mObservers = new ArrayList<>(); //attach:把订阅天气的人添加到列表中 public void attach(Observer observer) {//把观察者添加到观察者集合当中 mObservers.add(observer); } //detach:删除集合中指定的订阅天气的人 public void detach(Observer observer) { mObservers.remove(observer); } //notify:通知所有已经订阅天气的人,这个方法只有子类可以调用 protected void notifyObservers() {//向所有已注册的观察者发生消息 for (Observer observer : mObservers) { //在目标的Subject中调用update, observer.update(this);//将Subject对象传给观察者,以便获取目标的状态 } } }
具体的目标对象:
/** * 具体的目标对象:负责把有关状态存入到相应的观察者对象当中 */ public class ConcreateWeatherSubject extends WeatherSubject { //目标天气的内容信息 private String weatherContent; public String getWeatherContent() { return weatherContent; } //在保存目标状态的时候通知观察者 public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; //内容有了,说明天气更新了,通知所有订阅的人 this.notifyObservers();//状态发生改变就通知观察者 } }
观察者接口:
/** * 观察者接口:定义一个更新的接口给哪些在目标发生改变的时候被通知的对象 */ public interface Observer { /** * 更新的接口: * @param subject 传入的目标的对象:方便获取相应的目标对象的状态 */ void update(WeatherSubject subject); }
具体的观察者对象:
/** * 具体的观察者对象:实现更新的方法,使自身的状态和目标的状态保持一致 */ public class ConcreateObserver implements Observer { private static final String TAG = "ConcreateObserver"; //观察者的名字,是谁收到了这个信息,黄明的女朋友还是她老妈 private String observerName; //天气的内容,这个消息从目标出获取 private String weatherContent; //提醒的内容:黄明的女朋友提醒约会,而她老妈则提醒购物 private String remindThing; public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; } public String getRemindThing() { return remindThing; } public void setRemindThing(String remindThing) { this.remindThing = remindThing; } //获取目标类的状态同步到观察者的状态 @Override public void update(WeatherSubject subject) { //取出目标状态覆盖观察者的状态,使2者同步 //强转为具体的ConcreateSubject,因为状态保持在子类中,通过子类获取状态 weatherContent = ((ConcreateWeatherSubject)subject).getWeatherContent(); Log.i(TAG, "update: " + observerName + "收到了" + weatherContent + "," + remindThing); }
测试(调用这个方法即可):标准4步走
private void observer() { //1.创建目标 ConcreateWeatherSubject weather = new ConcreateWeatherSubject(); //2.创建观察者 ConcreateObserver observerGirl = new ConcreateObserver(); observerGirl.setObserverName("黄明的女朋友"); observerGirl.setRemindThing("我们的第一次约会,地点街心公园,不见不散哦"); ConcreateObserver observerMum = new ConcreateObserver(); observerMum.setObserverName("老妈"); observerMum.setRemindThing("是一个购物的好日子,明天去天虹扫货"); //3.注册观察者 weather.attach(observerGirl); weather.attach(observerMum); //4.目标发布天气 weather.setWeatherContent("明天天气晴朗,蓝天白云,气温28"); }
Last:本篇参照慕课网视频学习,有不懂的可以去慕课网看视频学习!
欢迎探讨学习,真心希望大家推荐好文共同成长!