使用Decorator模式实现日期选择组件(2)

1/5/2008来源:Java教程人气:5875


  实现日期选择
  实现了核心的日期选择面板,并将它做为一个可用Decorator 模式的接口。(在i/o例子中,所有的Decorate 对象都是inputStream 对象,因此可同等对待,所有的模式构造器参数都是InputStream 引 用,你可以在不知道包装对象时,用其他Decorator 来包装任何一个Decorator 。)
  
  public interface Date_selector
  {
    public static final int CHANGE_ACTION = 0;
    public static final int SELECT_ACTION = 1;
  
    public void addActionListener(ActionListener l);
    public void removeActionListener(ActionListener l);
  
    public Date get_selected_date();
    public Date get_current_date();
  
    /** Must work just like {@link Calendar#roll(int,boolean)} */
    public void roll(int flag, boolean up);
  
    /** Must work just like {@link Calendar#get(int)} */
    public int get(int flag);
  }
  
  Date_selector接口定义了2个静态值:CHANGE_ACTION和SELECT_ACTION,用于事件处理过程中(在下面将有更多例子)。接口也提供了添加与移除当选择日期时已激发的ActionListener对象的方法。最后它提供了模拟java.util.Calendar()方法通过增量(年、月)来推进日历并获取属性值(如当前月份和年份)的接口.
  我们返回动作监听:向按纽增加监听一样在日期选择中增加监听。
  
  Date_selector selector = new Date_selector_panel();
  selector.addActionListener
  (  new ActionListener()
    {  public void actionPerformed( ActionEvent e )
      {  // Do whatever you'd do to PRocess an event
      }
    }
  );
  
  监听策略采用的是观察者(Observer)模式。
  在两种情况下监听将被唤醒(actionPerformed()被调用),两者区别是通过发送 ActionEvent 对象,并传递给actionPerformed一个getID()消息。下面表进行了具体说明:
  
  动作事件:
  CHANGE_ACTION:当日历面板改变显示的月与年(典型的就是导航条要改变)的时候发送该事件。调用event.getActionCommand.getActionCommand()去获得发生改变后的当前月与年。你也可以调用get_current_date()获取当前用户选择的日期。
  SELECT_ACTION:当用户点击日期时发送时间,调用event.getActionCommand.getActionCommand()去获得选择日期的字符串形式。(这字符串和使用toString()得到相同的结构。)你也可以调用get_selected_date()获取改变后当前用户选择的日期。
  下面代码演示了这两种事件类型,它实现了当用户通过导航条改变月份Date_selector改变标签与用户点击面板改变日期的功能:
  Date_selector selector = new Date_selector_panel();
  JLabel moth_display = new JLabel();
  
  s.addActionListener
  (  new ActionListener()
    {  public void actionPerformed( ActionEvent e )
      {  if( e.getID() == Date_selector.CHANGE_ACTION )
          month_display.setText( e.getActionCommand() );
        else
          System.out.println( e.getActionCommand() );
      }
    }
  );
  
  所有实现了Date_selector接口,还继续了 JPanel类(或至少说是一些 Container 的衍生物)。代码要实现这个需求,以便日期选择器不用派生也可以当作一个JPanel使用,但是此时实现不了因为java.awt.Container不是一个接口.对于一个方法,假如要返回一个能看为日期选择器或容器,它将必须实现这两个类,这样是非法的,而且接口(Date_selector)不能继续于一个类(Container)。
  
  这个缺陷正好是一个很好的例子:这说明了有时为何难于在已经存在而没有正确使用接口的代码上改型"四人帮"模式。假如是我,我重制它并将 Container写成一个接口,实现 Container与Date_selector。(很明显,我无法改变java.*包)。这种类到接口重组是非常困难的,因为,所有的类代码不变而接口变化程序将会中断。
  
  引进c++风格的重载操作原因是通过重载操作"new"可以是重组变的轻易些。这种方式你可以新建(new)一个接口并且具有默认借口类的性质。java的解决方法是生成一“四人帮”工厂,它是比刚才那样假想的正确做法轻易多了。