记一次观察者模式的使用

作者: e4e52c116681 | 来源:发表于2018-12-25 19:34 被阅读26次

    一、引入:

    今天做播放器时碰到了一个小问题:
    有三个地方需要同一组数据,而且分属不同地方,如何同步?
    当然有很多方法可以实现,本文主要讲观察者模式,也算是回虐它吧(曾经被它吊打...)
    注意,本文使用的是测试代码,仅是模拟情况(Android上的使用道理是一致的,已实证)

    数据同步

    把问题简化为下面7个类:
    需求:数据在SongSubject中的改变,可以通知三个观察者,并同时更新数据

    问题抽离

    二、观察者模式:

    一对多--一人提供信息(Subject),多人需求信息(Observer),信息体(T)
    T发生改变时,由Subject统一提醒Observer


    1.接口层:Observer接口:(观察者)
    public interface Observer<T> {
        /**
         * 更新
         * @param t 观察变化的信息体
         */
        void update(T t);
    }
    

    2.接口层:Subject接口:(被观察者)
    public interface Subject<T> {
        /**
         * 观察者关联
         * @param o 待观察者(信息体)
         */
        void attach(Observer<T> o);
    
        /**
         * 观察者取消关联
         * @param o 待观察者()
         */
        void detach(Observer<T> o);
    
        /**
         * 当信息体更新时调用,用于通知观察者
         */
        void notifyObserver();
    }
    

    3.信息体(Song)
    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.信息提供者(被观察者实现类):
    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观察者实现类
    /**
     * 作者:张风捷特烈
     * 时间: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观察者实现类
    /**
     * 作者:张风捷特烈
     * 时间: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.主页面观察者实现类

    主要绑定逻辑在模仿的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.启动类:
    public class Boot {
        public static void main(String[] args) {
            HomeActivity activity = new HomeActivity();
            activity.onCreate();
        }
    }
    

    三、观察者模式分析

    1.运行结果如下图
    结果.gif
    2.分析:

    单看结果好像并没有什么特色,但是请注意:

    每次的印的三条数据分别来源于三个不同的类
    当你在update方法里用song对象控制视图显示时,只需要让被观察者更新数据就行了
    三个界面的信息会同步变化,这就是观察者模式优秀的地方
    毕竟实际中Pop弹框,Activity,Fragement分属不同类,能够这样统一变化会减少耦合
    

    3.小结

    设计模式还是在需要的时候能理解的清晰一些,干巴巴的看典例总感觉也就那样
    最近在做个人播放器玩一下,整个体系挺大的,也比较碎,应该不能成文了,等完善发后源码吧

    相关文章

      网友评论

        本文标题:记一次观察者模式的使用

        本文链接:https://www.haomeiwen.com/subject/dwlqlqtx.html