一、引入:
今天做播放器时碰到了一个小问题: 有三个地方需要同一组数据,而且分属不同地方,如何同步? 当然
有很多方法可以实现
,本文主要讲观察者模式
,也算是回虐它吧(曾经被它吊打...) 注意,本文使用的是测试代码,仅是模拟情况
(Android上的使用道理是一致的,已实证)
数据同步
把问题简化为下面7个类: 需求:数据在SongSubject中的改变,可以通知三个观察者,并同时更新数据
问题抽离
二、观察者模式:
一对多--一人提供信息(
Subject
),多人需求信息(Observer
),信息体(T
) T发生改变时,由Subject统一提醒Observer
1.接口层:Observer接口:(观察者)
代码语言:javascript复制public interface Observer<T> {
/**
* 更新
* @param t 观察变化的信息体
*/
void update(T t);
}
2.接口层:Subject接口:(被观察者)
代码语言:javascript复制public interface Subject<T> {
/**
* 观察者关联
* @param o 待观察者(信息体)
*/
void attach(Observer<T> o);
/**
* 观察者取消关联
* @param o 待观察者()
*/
void detach(Observer<T> o);
/**
* 当信息体更新时调用,用于通知观察者
*/
void notifyObserver();
}
3.信息体(Song)
代码语言:javascript复制public class Song {
private String title;
private String singer;
private long seek;
public Song(String title, String singer, long seek) {
this.title = title;
this.singer = singer;
this.seek = seek;
}
//set、get、toString省略...
}
4.信息提供者(被观察者实现类):
代码语言:javascript复制public class SongSubject implements Subject<Song>{
private List<Observer<Song>> mObservers = new ArrayList<>();//观察者对象集合
private Song mSong;
@Override
public void attach(Observer<Song> observer) {
mObservers.add(observer);
}
@Override
public void detach(Observer<Song> observer) {
mObservers.remove(observer);
}
@Override
public void notifyObserver() {
for (Observer<Song> o : mObservers) {
o.update(mSong);
}
}
/**
* 设置信息--通知所有观察者
* @param song
*/
public void setSong(Song song) {
mSong = song;
this.notifyObserver();
}
}
5.Pop观察者实现类
代码语言:javascript复制/**
* 作者:张风捷特烈
* 时间:2018/12/24 0024:21:27
* 邮箱:1981462002@qq.com
* 说明:观察者:Pop
*/
public class PopPager implements Observer<Song> {
@Override
public void update(Song song) {
//TODO:更新时的视图渲染
System.out.println("PopPager:" song);
}
}
6.Fragment观察者实现类
代码语言:javascript复制/**
* 作者:张风捷特烈
* 时间:2018/12/24 0024:21:27
* 邮箱:1981462002@qq.com
* 说明:观察者:Fragment
*/
public class HomeListFragment implements Observer<Song> {
@Override
public void update(Song song) {
//TODO:更新时的视图渲染
System.out.println("HomeListFragment:" song);
}
}
7.主页面观察者实现类
代码语言:javascript复制主要绑定逻辑在模仿的onCreate里,当然mpv里,你可以根据实际情况
/**
* 作者:张风捷特烈
* 时间:2018/12/24 0024:21:27
* 邮箱:1981462002@qq.com
* 说明:观察者:Activity
*/
public class HomeActivity implements Observer<Song> {
private int seek;
public void onCreate() {
SongSubject songSubject = new SongSubject();
PopPager popPager = new PopPager();//常见Pop
HomeListFragment homeListFragment = new HomeListFragment();//创建Fragment
songSubject.attach(this);//HomeActivity观察信息
songSubject.attach(homeListFragment);//homeListFragment观察信息
songSubject.attach(popPager);//popPager观察信息
Song song = new Song("勇气", "葛强丽", seek);//信息模拟
Timer timer = new Timer();//计时器轮训任务
timer.schedule(new TimerTask() {
public void run() {
song.setSeek(seek );//修改信息
songSubject.setSong(song);//设置信息,通知所有观察者
}
}, 0, 1000);
}
@Override
public void update(Song song) {
//TODO:更新时的视图渲染
System.out.println("HomeActivity:" song);
}
}
8.启动类:
代码语言:javascript复制public class Boot {
public static void main(String[] args) {
HomeActivity activity = new HomeActivity();
activity.onCreate();
}
}
三、观察者模式分析
1.运行结果如下图
结果.gif
2.分析:
代码语言:javascript复制单看结果好像并没有什么特色,但是请注意:
每次的印的三条数据分别来源于三个不同的类
当你在update方法里用song对象控制视图显示时,只需要让被观察者更新数据就行了
三个界面的信息会同步变化,这就是观察者模式优秀的地方
毕竟实际中Pop弹框,Activity,Fragement分属不同类,能够这样统一变化会减少耦合
3.小结
设计模式还是在需要的时候能理解的清晰一些,干巴巴的看典例总感觉也就那样 最近在做个人播放器玩一下,整个体系挺大的,也比较碎,应该不能成文了,等完善发后源码吧