设计模式第三天-亲力亲为实现观察者模式

在上一边文章中,和大家分享了基于java内置实现的观察者模式。在本次分享中呢,将会是一个完全自己定义的一个观察者模式。我们还是以新闻报社为例子。

在这里,我们将报社(被观察者)成为主题(Subject),观察者成为(Observer),在第一篇文章中,我们讨论了策略模式,也就是我们要针对接口编程,所以我们首先来定义两个接口,一个是主题接口,另一个是观察者接口。

主题接口有什么内容呢?首先我们应该允许增加新的注册用户(订阅报社的用户),还有用户进行取消注册,还有就是当有新的数据的时候,应该能够通知所有的注册了的用户。因此应该有三个方法。

package demo;
/**
 * 观察者模式的主题接口
 * @author wangpeiyu
 *
 */
public interface ISubject {
	public void register(IObserver observer);
	public void remove(IObserver subject);
	public void notifys();
}

观察者接口应该有什么呢?首先最重要的就是更新相关的数据了。

更新有两个方法:

方法一:直接通过update方法,将所有的数据以参数的形式传递过来

方法二: 直接将持有数据的主题(可观察者,也就是报社)的对象传递过来,观察者自己通过该对象get想要的数据。

package demo;
/**
 * 观察者模式的观察者接口
 * @author wangpeiyu
 *
 */
public interface IObserver {
	public void update(String news);
	public void update(ISubject subject);
}

下面我们来编写主题(可观察者)的实现类。

除了要有接口的注册、取消注册和通知所有用户的方法外,还要什么方法呢?

我们肯定要有一个更新数据然后触发通知所有用户方法的方法,这里我们就用updateNews(),更新新闻的方法,来表示数据发生了改变,要通知相关的用户了。

package demo;
import java.util.ArrayList;
public class Subject implements ISubject {
	//维护观察者的数组,可以通过遍历整个数组,达到通知所有注册了的用户
	private ArrayList<IObserver> observerList;
	//新闻信息
	private String news;
	
	public Subject() {
		// TODO Auto-generated constructor stub
		observerList = new ArrayList<IObserver>();
		news="";
	}
	public void updateNews(String news){
		this.news=news;
		notifys();//更新了新闻之后,应该通知所有的一已经注册了的用户,即观察者
	}
	/**
	 * 返回新的新闻信息
	 * 当在notifys中使用的是第一种传递方式的时候,可以使用这个方法,但是,此方法必须要设置为public
	 * 该方法的好处在于,用户可以自定义的获取自己想要的信息
	 * 但是将本主题对象传递过去,容易暴露信息
	 * 如果使用的是第二种方式的时候,可以直接将新的新闻信息传递出去,此时getNews这个方法可以是私有的
	 * 这个方法的好处在于,只将所有数据传递出去,不容易暴露主题对象的信息
	 * 不足是全部信息都传递出去,有些是用户不需要的
	 * 
	 * @return
	 */
	public String getNews(){
		return news;
	}
	
	@Override
	public void notifys() {
		// TODO Auto-generated method stub
		for(IObserver observer:observerList)
		{
			observer.update(this);//这是一种传递方式
			observer.update(news);//这是另一种方式
		}
	}
	/**
	 * 注册观察者
	 */
	@Override
	public void register(IObserver observer) {
		// TODO Auto-generated method stub
		if(!observerList.contains(observer))
		{
			observerList.add(observer);
		}
	}
	/**
	 * 观察者取消注册
	 */
	@Override
	public void remove(IObserver observer) {
		// TODO Auto-generated method stub
		//找到要取消注册的观察者的索引
		//如果索引为-1,则表示该观察者还没有注册,所以不用进行取消注册
		//否则就是已经注册了,然后进行取消
		int index = observerList.indexOf(observer);
		if(index!=-1)
		{
			observerList.remove(index);
		}
	}
}

接着我们再来实现观察者的方法。方法注释已经写得比较详细了。

package demo;

public class Observer implements IObserver {
	private String name;
	private ISubject subject;
	/**
	 * 为什么要传递Subject对象过来呢????
	 * 大家可以思考。
	 * 我个人觉得,传递Subject对象过来,可以直接在观察者中增加注册和取消注册的方法,然后在方法里面调用Subject进行注册
	 * 这样的好处是,可以直接通过观察者就可以完成了自身的注册和取消注册
	 * 可以避免要注册的时候,直接使用Subject类注册再传递一个观察者过去,维护性不强
	 * @param name
	 * @param subject
	 */
	public Observer(String name,ISubject subject) {
		// TODO Auto-generated constructor stub
		this.name = name;
		this.subject = subject;
	}
	@Override
	public void update(String news) {
		// TODO Auto-generated method stub
		System.out.println(name+"  "+news+"\n");//直接将传递过来的,自己感兴趣的数据进行输出

	}
	@Override
	public void update(ISubject subject) {
		// TODO Auto-generated method stub	
		if(subject!=null)
		{
			if(subject instanceof Subject)
			{
				Subject subjectEntires = (Subject)subject;
						System.out.println(name+"  "+subjectEntires.getNews()+"\n");//这时候通过暴露出来的方法进行获取
			}
		}
	}
	/**
	 * 观察者的方法,实现注册
	 * 本质上和直接使用Subject在程序中传递一个观察者过去是一样的
	 */
	public void register(){
		subject.register(this);
	}
	/**
	 * 观察者的方法,实现取消注册
	 */
	public void remove(){
		subject.remove(this);
	}
}

下面我们再来编写一个测试代码

package demo;
public class main {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//新建一个新闻服务
		Subject subject = new Subject();
		//新建用户,观察者
		Observer observer1 = new Observer("小王",subject);
		Observer observer2 = new Observer("小黄",subject);
		Observer observer3 = new Observer("小陈",subject);
		Observer observer4 = new Observer("小吴",subject);
		/**
		 * 用户注册,也就是订阅了新闻服务
		 */
		observer1.register();
		observer2.register();
		observer3.register();
		observer4.register();
		//更新新闻,然后主题(被观察者)告诉所有注册了的用户
		subject.updateNews("你好,从你的全世界路过上映了!");
		System.out.println("A day later\n");
		//小王和小黄取消了关注
		observer1.remove();
		observer2.remove();
		System.out.println("小王和小黄取消了订阅,将不会在收到新的新闻了\n");
		subject.updateNews("你好,火锅英雄上映啦!!!");
	}
}

结果如图:

这就是自定义的观察者模式。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值