JAVA中的观察者机制在绘图程序中的应用

 
JAVA 中的观察者机制在绘图程序中的应用
java.util.*包中提供了一个有趣的类:Observable类,和一个Observer接口。利用这两个类我们可以把一个类对象中的信息更改传递给其他许多类的对象,然后在做出进一步的处理。这种机制我们可以成为观察者/被观察者机制,或者称为文档(模型)/视图机制。
请看下面的代码:我们设计了三个类:一个类的对象充当被观察者的角色,或者说是充当模型的角色——BeingWatched.java;一个类的对象充当观察者的角色,或者说是充当视图的角色——Watcher.java;还有最后一个测试类——Testing.java。让我们看看这三个类如何工作。
1、   被观察者类(模型类)的实现
在观察者机制中,被观察者类需要继承自java.util.Observable类。在Observable类中,有以下几个常用的方法:
setChanged
protected void setChanged()
Marks this Observable object as having been changed; the hasChanged method will now return true.
这个方法,可以将一个Observable对象标记为可变化的对象。
 
notifyObservers
public void notifyObservers(Object arg)
If this object has changed, as indicated by the hasChanged method, then notify all of its observers and then call the clearChanged method to indicate that this object has no longer changed.
Each observer has its update method called with two arguments: this observable object and the arg argument.
Parameters:
arg - any object.
这个方法,可以将任何Observable对象的更改消息传递给Observer对象,即将对象的变化消息传递观察者对象,以后由观察者对象表现被观察者的变化。
 
addObserver
public void addObserver(Observer o)
Adds an observer to the set of observers for this object, provided that it is not the same as some observer already in the set. The order in which notifications will be delivered to multiple observers is not specified. See the class comment.
Parameters:
o - an observer to be added.
Throws:
NullPointerException - if the parameter o is null.
这个方法可以在Observable对象上添加一个Observer对象,即由被观察者的对象为自己设定一个观察者对象,由该观察者对象负责处理自己的信息变化。
 
用户定义的被观察者类
package com.libin.chapter15.obv;
 
import java.util.*;
 
public class BeingWatched extends Observable{
    void counter( int period){
       for (;period>=0;period--){
           // 设置当前对象为可变化的对象
           setChanged();
           // 消息传递机制,通知观察者我要变化
           notifyObservers( new Integer(period));
           // 线程处理
           try {
              Thread.sleep(1000); // 休眠 1 秒钟,再运行
           } catch (InterruptedException e){
              System. out .println( "sleep interrupted" );
           }
       }
    }
}
 
2、   观察者类(视图类)的实现
充当观察者的类需要实现Observer接口。在Observer接口中有一个void update(Observable o, Object arg)方法,利用这个方法可以表现被观察对象的信息变化。
update
void update(Observable o,
            Object arg)
This method is called whenever the observed object is changed. An application calls an Observable object's notifyObservers method to have all the object's observers notified of the change.
Parameters:
o - the observable object.
arg - an argument passed to the notifyObservers method.
这个方法是在任何被观察的对象发生信息变化时被JAVA系统自动调用的。但是需要注意,只有在被观察的对象上添加了观察者对象,并且被观察者对象将自己设置为可变对象后,调用了 notifyObserver(s)方法后,update()方法才会被调用。
用户定义的观察者类
package com.libin.chapter15.obv;
 
import java.util.*;
import java.util.Observable;
 
public class Watcher implements Observer{
       //用来表现模型对象的变化过程
       public void update(Observable obj,Object arg){
              System.out.println("update() called,count is: "+((Integer)arg).intValue());
       }
}
 
3、   测试类的实现
在测试类中,我们创建了一个观察者对象,创建了一个被观察者对象,并且在被观察者对象上通过调用addObserver()方法添加一个观察者对象。
package com.libin.chapter15.obv;
 
import java.util.*;
 
public class ObserverDemo{
    public static void main(String args[]){
       BeingWatched observed= new BeingWatched();
       Watcher observing= new Watcher();
      
       /*Add the observing to the list of observers for observed object. */
       // 在模型对象上添加观察者对象
       observed.addObserver(observing);
       // 模型对象调用自己的业务处理方法
       observed.counter(10);
      
    }
}
 
 
程序运行结果:
 
 
 
 
 
 
 
 
 
 
通过上面的一个实例大家了解了观察者机制的应用,下面我们来实现一个绘图程序的基本模型,体验一下观察者机制在绘图程序中的使用。
1、创建一个基本的JFrame对象
package com.libin.chapter19.exec1;
 
import java.awt.BorderLayout;
import java.awt.Container;
 
import javax.swing.JFrame;
 
public class MyFrame extends JFrame{
      
       Container content;
       MyViewer view;
       public MyFrame(){
              this.setTitle("一个基础的绘图程序测试");
              this.setBounds(100,150,400,300);
              this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              content=this.getContentPane();
              view=new MyViewer();
              content.add(view,BorderLayout.CENTER);
             
              this.setVisible(true);
             
       }
 
}
程序运行原理说明:MyFrame类主要的职责是用来创建程序的运行主界面,以后的绘图工作区在这个主界面上完成。但是在MyFrame类的容器中,我们添加了一个负责显示绘图工作区的观察类类MyViewer的对象,绘图模型的变化需要由MyViewer类的对象负责表现出来。
2、创建绘图模型类
package com.libin.chapter19.exec1;
 
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Observable;
 
import com.libin.chapter19.demo3.Element;
import java.awt.geom.*;
public class MyModel extends Observable{
   
    public boolean remove(Line2D.Double line) {
        boolean removed = elementList .remove(line);
        if (removed) {
          setChanged();
          notifyObservers(line.getBounds());
        }
 
        return removed;
     }
     
      public void add(Line2D.Double line) {
        elementList .add(line);
        setChanged();
        notifyObservers(line.getBounds());
     }
 
      public Iterator getIterator() {
        return elementList .listIterator(); 
     }
      // 基于链表结构实现的集合类
      protected LinkedList elementList = new LinkedList();
 
   
   
}
 
程序工作原理:绘图模型类 MyModel ,通过 LinkedList 集合类的对象负责存储绘制的模型。之所以使用集合类的对象存储绘制的形状模型,主要是因为,我们在绘图工作区上绘制的不仅仅只有一个图形的形状。我们绘制的每一个形状都需要在绘图工作区中显示出来,所以需要使用集合类来对形状进行控制。
3、创建表现绘图结果的观察者类
package com.libin.chapter19.exec1;
 
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.text.DateFormat;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
 
import javax.swing.JComponent;
import javax.swing.event.MouseInputAdapter;
 
public class MyViewer extends JComponent implements Observer {
 
    MyModel model = new MyModel();
 
    public MyViewer() {
       MyMouserHandler handler= new MyMouserHandler();
       this .addMouseListener(handler);
 
    }
   
   
    public void paint(Graphics g) {
        Graphics2D g2D = (Graphics2D)g;                // Get a Java 2D device context
 
        Iterator elements = model .getIterator();
        Line2D.Double element;                                    // Stores an element
 
        while (elements.hasNext()) {                         // Go through the list
          element = (Line2D.Double)elements.next();               // Get the next element
          g2D.setPaint(Color. red );                 // Set the element color
          // 绘制最终的形状
          g2D.draw(element);
          // Draw its shape
        }
     }
   
   
 
    public void update(Observable o, Object obj) {
      
       if ((Line2D.Double)obj== null ){
           repaint();
       }
 
    }
 
    public class MyMouserHandler extends MouseInputAdapter {
 
       private Point start ; // Stores cursor position on press
 
       private Point last ; // Stores cursor position on drag
 
       private Line2D.Double tempElement ; // Stores a temporary element
 
       private boolean button1Down = false ; // Flag for button 1 state
 
       private Graphics2D g2D = null ;
 
       public void mousePressed(MouseEvent e) {
           start = e.getPoint(); // Save the cursor position in start
           if ( button1Down = (e.getButton() == MouseEvent. BUTTON1 )) {
              System. out .println( " 鼠标左键被按下 " );
              g2D = (Graphics2D) getGraphics();
              g2D .setPaint(Color. blue );
 
           }
       }
 
       public void mouseReleased(MouseEvent e) {
          
           last = e.getPoint();
           tempElement = createElement( start , last );
           g2D .draw( tempElement );
          
           if ( button1Down = (e.getButton() == MouseEvent. BUTTON1 )) {
              button1Down = false ; // Reset the button 1 flag
              System. out .println( " 鼠标左键已经被释放 " );
              if ( tempElement != null ) {
 
                  model .add( tempElement ); // Add element to the model
                  tempElement = null ; // No temporary now stored
              }
              // 释放绘图对象,清理绘图环境
              if ( g2D != null ) { // If there's a graphics context
                  g2D .dispose(); // ...release the resource
                  g2D = null ; // Set field to null
              }
              start = last = null ; // Remove the points
           }
       }
 
       private Line2D.Double createElement(Point start, Point end) {
 
           return new Line2D.Double(start, end);
           // We should never get to here
 
       }
 
    }
 
}
 
程序工作原理:在 MyViewer 类中负责处理鼠标绘图事件,并且还需要观察绘图模型的变化,将这种变化在主界面上表现出来。
4、   创建最终的应用程序类
package com.libin.chapter19.exec1;
 
public class MyApp {
 
    /**
      * @param args
      */
    public static void main(String[] args) {
       // TODO Auto-generated method stub
      
       MyApp app= new MyApp();
       app.init();
    }
 
   
    public void init(){
       MyFrame myFrame= new MyFrame();
    }
}
 
这个绘图程序的基本模型完成了,但是我们还需要有几点思考:
1、   程序本身功能不是很健全,主要是体验一个模型的使用。如果需要能够绘制多种几何形状的话,可以编写专门的一个类来负责各种几何形状的生成。然后在相应鼠标事件处理时,根据需要绘制的形状调用相关的几何形状生成算法,生成几何形状对象后,添加到MyModel类的集合类中去。
2、   在图形的绘图过程中,如果需要能够看到形状的动态生成过程,就需要在处理鼠标绘图事件时,处理鼠标的拖拽方法,并且在几何形状的生成算法中要处理modify()方法;否则用户将不会看到形状的生成过程。
更完善的程序,由于篇幅有限,我没有在这个给出。感兴趣的朋友可以发邮件给我: libin_qm@163.com。我将会给你回复。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值