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

观察者模式

以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的实例添加这些观察者即可。程序具有了更好的可扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值