我对观察者模式的理解

系统 1812 0

前言

     一直很少动手写文档,觉得自己只是一个新手,对很多技术点或者概念理解的不透彻,没多少自信。二来,做程序遇到困难时,在论坛上找到的几乎都是通篇的代码,只能一行行解读代码,自己自圆其说。我不太喜欢这种模式,但是又不知道如何找到详细的资料,天天百度,费力不讨好。在图书馆找参考书,大多都是些基础的东西,也没什么帮助。

    昨天,老师布置了一些作业,问我们应不应该强制?回来后我想了想,还是觉得不该强制,如果你爱JAVA,你自己会花时间在上面的。写文档倒是很有必要的。写文档,一来可以记录你的学习历程,二来可以暴露一些问题,如果你讲不清楚一个问题,很有可能时因为你对该问题的理解不透彻。

  

   今天,我要叙述的内容是观察者模式,也称发布/订阅模式,监听器模式

  

观察者模式是软体设计模式的一种。在此种模式中,一个目标物件(被观察者)管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。

 

   叙述该问题,通篇叙述不如通过实例来的易理解,不用实例,估计我也讲不清楚

  

   例:给一个JFrame上的JTree添加节点,通过线程给JTree添加5个节点

 

1.直接调用模式

     学习这么久,老师从没有讲过搭建模型,记得在写五子棋游戏的时候,那时候写的是郁闷的很,每添加一个功能时,都要修改好几个类。类与类的耦合非常高。    

    实现JFrame的JTree上添加节点:

    思路:用线程来模拟给JTree添加节点,在线程的构造器中传入JTree对象。

     

    /**********************
 *此类为消息类,用来作为树节点
 */
public class Msg {

	private String text;
	
	public Msg(String text){
		this.text = text;
	}
	
	//重写toString方法,设置节点显示内容
	public String toString(){
		return this.text;
	}
}

  

 

  线程类:

    

    public class TestThread extends  Thread{

	private JTree tree;
	
	public TestThread(JTree tree){
	    //传入JTree对象   
		this.tree = tree ;
	}
	
	
	public void run(){
		
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		
		for(int i=0;i<5;i++){
			
			Msg msg = new Msg("第"+(i+1)+"个节点");
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(msg);
			//添加节点
			root.add(node);
			//刷新树
			javax.swing.SwingUtilities.updateComponentTreeUI(tree);
			//延时1S
			try{
				Thread.sleep(1000);
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	
  

 测试界面类:

  

    	public static void main(String[] args){
		
		JFrame fr = new JFrame("Test_1");
		fr.setSize(300, 300);
		fr.setDefaultCloseOperation(3);
		fr.setLayout(new FlowLayout(FlowLayout.LEFT));
		
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
		JTree tree = new JTree(root);
		fr.add(tree);
		
		new TestThread(tree).start();
		
		fr.setVisible(true);
		
	}
  

 

总结1 :软件是应用户需要而编写的,肯定会经常修改。这种模式由于界面类和实现类之间的高耦合,要改界面类和实现

       类都要改, 不利于程序的修改和扩展。

          怎样才能避免这种牵一发动全身的问题呢?

           想想,如果将具体对象间的依赖关系转化为接口实现的抽象关系会怎样,就可将界面类和实现类分别封装,使相互

       独立,各自修改互补影响。对于本例,在线程中添加一个监听器队列,当产生事件时通知队列中的各监听器即可,这

        需要有添加,移除,通知监听器的方法。

 

          可将上面的代码修改一下

观察者模式

     首先需要定义消息处理接口

    public interface InListener {

	public void actionPerformed(Msg msg);
	
}
  

   根据需要编写实现类,本例中:

   MyJTreeListener

  

    public class MyJTreeListener implements InListener{

	
	private JTree tree;
	private DefaultMutableTreeNode root;
	
	public MyJTreeListener(JTree tree){
		
		this.tree = tree;
		root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		
	}
	
	
	public void actionPerformed(Msg msg) {
		
		DefaultMutableTreeNode node = new DefaultMutableTreeNode(msg);
	    root.add(node);
	    javax.swing.SwingUtilities.updateComponentTreeUI(tree);
	}

}

  

 线程类:

 

    public class TestThread extends  Thread{
    
	//监听器队列
	private ArrayList<InListener> list ;
	
	public TestThread(){
	    //初始化监听器队列
		list = new ArrayList();
	}
	
	
	public void run(){
		
			for(int i=0;i<5;i++){
				
				Msg msg = new Msg("第"+(i+1)+"条消息");
				//通知各监听器
				this.fireInListener(msg);
				
				//延时1S
				try{
					Thread.sleep(1000);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		
	}
	
	/***********************8
	 * 通知所有消息监听器
	 * @param msg:消息
	 */
	public void fireInListener(Msg msg){
		
		for(int i=0;i<list.size();i++){
			InListener listener = list.get(i);
			listener.actionPerformed(msg);
		}
	}
	
	/***************************
	 * 添加事件监听器
	 * @param l:要添加的监听器
	 * @return:添加结果
	 */
	public boolean addListener(InListener l){
		
		return list.add(l);
		
	}
	/****************************
	 * 移除事件监听器
	 * @param l:要移除的监听器
	 * @return:移除结果
	 */
	public boolean removeListener(InListener l){
		
		return list.remove(l);
	}
	
	
  

 测试:

  

    	public static void main(String[] args){
		
		JFrame fr = new JFrame("Test_2");
		fr.setSize(300, 300);
		fr.setDefaultCloseOperation(3);
		fr.setLayout(new FlowLayout(FlowLayout.LEFT));
		
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
		JTree tree = new JTree(root);
		fr.add(tree);
		
		TestThread nt = new TestThread();
		//注册监听器
		nt.addListener(new MyJTreeListener(tree));
		nt.start();
		
		
		fr.setVisible(true);
		
	}
  

  总结2: 这样,线程对象和具体的事件处理对象就可以相互独立的修改    但实际上这是一种具体对抽象的关系,可以进一步将事件产生类(本例中为线程)进行抽象,变为抽象对抽象的关系,毕竟现实中的事件产生可以有很多种情况,往往风马牛不相及。

 

    只需再定义一个事件产生接口即可:

    InEventSource

   

    public interface InEventSource {

	public ArrayList<InListener> list = new ArrayList();
	
	public boolean addListener(InListener l);
	
	public boolean removeListener(InListener l);
	
	public void fireInListener(Msg msg);
	
	
}

  

 

线程类:

  

    public class TestThread extends  Thread implements InEventSource{

	
	public void run(){
		
			for(int j=0;j<5;j++){
				
				Msg msg = new Msg("第"+(j+1)+"条消息");
				
				this.fireInListener(msg);
				
				//延时1S
				try{
					Thread.sleep(1000);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		
	}
	
	
	public void fireInListener(Msg msg){
		
		for(int i=0;i<list.size();i++){
			InListener listener = list.get(i);
			listener.actionPerformed(msg);
		}
	}
	
	
	public boolean addListener(InListener l){
		
		return list.add(l);
		
	}
	
	public boolean removeListener(InListener l){
		
		return list.remove(l);
	}
	
  

 

测试不变

 

总结3: 观察者模式所进行的工作就是解耦,就是将具体的对象之间的关系进行抽象,变为抽象对抽象的关系,降低具体对象间的依赖性,从而实现良好的修改,扩充性。其实,就是让我们懂得封装的重要性,教我们如何封装。

 

 

什么时候应该采用观察者模式

     我觉得,当一个对象改变时,同时要改变其他对象,而且不知道要改变多少其他对象时,应该考虑采用观察者模式。

 

 

由于我的水平有限,讲的不是很清楚,如果有错的,或是不好的地方,欢迎指出批评。

 

附上 《大话设计模式》下载链接 书中第14章有很生动的讲解

http://dl.iplaysoft.com/files/742.html

我对观察者模式的理解


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论