精通23种设计模式——观察者模式

来源:互联网 发布:.net core 2.0 数据库 编辑:程序博客网 时间:2024/06/09 21:39

观察者模式

以NBA球星和媒体之间的关系为例,球星的一举一动都在媒体的关注之下,比如,球星去夜店做了什么什么事情,媒体都会第一时间给出报导。
那么这里球星就属于被观察者,媒体属于观察者。

需要定义一个球员接口,包含球员可能出现的各种情况:

public interface BasketballPlayer {    /**     * 球员去夜店     */    public void goNightclub();    /**     * 球员发推特     */    public void publishTwitter();}

其次需要定义一个新闻媒体的接口,每当球员有新的情况,就会更新消息:

public interface NewsMedia {    public void update(String message);}

我们以哈登去夜店,发推特为例,其中还需要为哈登单独定义两个flag变量,是不是去夜店啦,是不是发推特啦,以及他们对应的get,set方法。

public class Harden implements BasketballPlayer{    private boolean isGoNightclub = false;    private boolean isPublishTwitter = false;    /**     * 哈登去夜店了     */    public void goNightclub() {        setGoNightclub(true);    }    /**     * 哈登发推特了     */    public void publishTwitter() {        setPublishTwitter(true);    }    public boolean isGoNightclub(){        return isGoNightclub;    }    public void setGoNightclub(boolean isGoNightclub){        this.isGoNightclub = isGoNightclub;    }    public boolean isPublishTwitter(){        return isPublishTwitter;    }    public void setPublishTwitter(boolean isPublishTwitter){        this.isPublishTwitter = isPublishTwitter;    }}

新闻媒体以ESPN为例:

public class ESPN implements NewsMedia{    public void update(String type) {        System.out.println(type);    }}

ESPN肯定不会一天24小时都花在哈登身上,于是,ESPN雇了一名记者Jack,全程跟踪报道哈登,一有消息就通知ESPN。

public interface Journalist extends Runnable{}/** * Created by lovekun on 2016/10/21. * */public class Jack implements Journalist, Runnable{    private BasketballPlayer mBasketballPlayer;    private NewsMedia mNewsMedia;    private String mType;    /**     *     * @param basketballPlayer     * @param newsMedia     * @param type  监控内容     */    public Jack(BasketballPlayer basketballPlayer, NewsMedia newsMedia, String type){        this.mBasketballPlayer = basketballPlayer;        this.mNewsMedia = newsMedia;        this.mType = type;    }    public void run() {        while (true){            synchronized (mBasketballPlayer){                if (mType.equals("Nightclub")){                    if (((Harden)mBasketballPlayer).isGoNightclub()){                        mNewsMedia.update("哈登去夜店了");                        ((Harden) mBasketballPlayer).setGoNightclub(false);                    }                }else if(mType.equals("publishTwitter")){                    if (((Harden)mBasketballPlayer).isPublishTwitter()){                        mNewsMedia.update("哈登发推特了");                        ((Harden) mBasketballPlayer).setPublishTwitter(false);                    }                }            }        }    }}

这里需要注意更新哈登信息和状态,需要放在同步代码块中,以防哈登离开一家夜店后,Jack还没有来及更新它的状态,哈登又进了另一家夜店,导致Jack无法及时更新信息和通知ESPN。

剩下的就是场景类了:

/** * Created by lovekun on 2016/10/21. * * 观察者模式场景类 */public class ObserverClient {    public static void main(String[] args) throws Exception{        BasketballPlayer mBasketballPlayer = new Harden();        NewsMedia mESPN = new ESPN();        Journalist journalistForNightclub = new Jack(mBasketballPlayer, mESPN, "Nightclub");        Thread threadForNightclub = new Thread(journalistForNightclub);        threadForNightclub.start();        Journalist journalistForPublishTwitter = new Jack(mBasketballPlayer, mESPN, "publishTwitter");        Thread threadForPublishTwitter = new Thread(journalistForPublishTwitter);        threadForPublishTwitter.start();        Thread.sleep(2000);        mBasketballPlayer.goNightclub();        Thread.sleep(2000);        mBasketballPlayer.goNightclub();        Thread.sleep(2000);        mBasketballPlayer.publishTwitter();        Thread.sleep(2000);        mBasketballPlayer.goNightclub();    }}

这种方法通过一个线程里的死循环不断监听,如果监听的东西多了,会导致系统的性能极差。
既然球员一有动作,新闻媒体就会知道,可以把新闻媒体聚合到球员类中。
仍然定义一个球员接口和新闻媒体接口

/** * Created by lovekun on 2016/10/21. */public interface BasketballPlayer {    /**     * 球员去夜店     */    public void goNightclub();    /**     * 球员发推特     */    public void publishTwitter();}
/** * Created by lovekun on 2016/10/21. */public interface NewsMedia {    public void update(String message);}

实现一个被观察者的接口,包含对观察者的添加,删除,通知方法。

/** * Created by lovekun on 2016/10/21. */public interface Observable {    public void addObserver(NewsMedia newsMedia);    public void delObserver(NewsMedia newsMedia);    public void notifyObservers(String message);}

实例如一个巨星哈登,他实现了球员接口,同时也是一个被观察者,实现了被观察者接口:

/** * Created by lovekun on 2016/10/21. */public class Harden implements BasketballPlayer, Observable{    private ArrayList<NewsMedia> newsMedias = new ArrayList<NewsMedia>();    /**     * 哈登去夜店了     */    public void goNightclub() {        notifyObservers("哈登去夜店了");    }    /**     * 哈登发推特了     */    public void publishTwitter() {        notifyObservers("哈登发推特了");    }    public void addObserver(NewsMedia newsMedia) {        this.newsMedias.add(newsMedia);    }    public void delObserver(NewsMedia newsMedia) {        this.newsMedias.remove(newsMedia);    }    public void notifyObservers(String message) {        for (NewsMedia newsMedia : newsMedias){            newsMedia.update(message);        }    }}

关注哈登的媒体有很多,ESPN、腾讯等等

/** * Created by lovekun on 2016/10/21. */public class ESPN implements NewsMedia {    public void update(String message) {        System.out.println("ESPN新闻:" + message);    }}
/** * Created by lovekun on 2016/10/21. */public class Tengxun implements NewsMedia{    public void update(String message) {        System.out.println("腾讯新闻:" + message);    }}

剩下的就是场景类的实现:

/** * Created by lovekun on 2016/10/21. * * 观察者模式场景类 */public class ObserverClient {    public static void main(String[] args) throws Exception{        BasketballPlayer harden = new Harden();        ((Harden) harden).addObserver(new ESPN());        ((Harden) harden).addObserver(new Tengxun());        harden.goNightclub();        harden.publishTwitter();    }}

这样,如果还有虎扑,新浪等媒体也关注哈登,这些新闻媒体只需要实现NewMedia接口,并且harden的实例添加这些观察者即可。程序具有了更好的可扩展性。

  • 参考内容: 《涉及模式之禅》
  • 源码下载: 观察者模式源码
0 0
原创粉丝点击