使用Decorator模式(二)
浏览:42日期:2023-03-08
内容: 构造函数将被修饰的组件赋值给child变量,并且将这个组件作为一个子组件增加给装饰者。注意,我们使用了BorderLayout作为装饰者的布局。这意味着被增加的这个JComponent将占据这个装饰者的整个区域。 现在,让我们关注一下paint方法。它首先调用了父类的paint方法。这-步操作将画出装饰者,在第一次得到装饰者的长宽以后,我们在装饰者所在区域的边缘画一个长方形。Figure 1 shows a JFrame with three components:· An instance of JBorderLabel. · A decorated JLabel. · A decorated JCheckBox. IMG http://www.onjava.com/onjava/2003/02/05/graphics/figure1.png[/IMG]Figure 1 -- comparing subclassing and the Decorator pattern 像图1所显示的那样,JBorderLabel的一个实例和一个被装饰过的JLabel对象实例从外表看没有什么不同。这说明,Decorator模式可以作为子类化的一个替代方案。第三个组件证明,你能够使用同一个装饰者去扩展不同对象的实例的行为。从这点来看,装饰者是一个(超类)superior,因为仅仅需要创建一个类(BorderDecorator)就可以扩张不同类型的多个对象的功能。 清单3显示了图1中的JFrame类的实现代码。 列表 3 -- using the BorderDecorator classpackage decorator;import java.awt.*;import javax.swing.*;import java.awt.event.*;public class Frame1 extends JFrame { JBorderLabel label1 = new JBorderLabel('JLabel Subclass'); BorderDecorator label2 = new BorderDecorator(new JLabel('Decorated JLabel')); BorderDecorator checkBox1 = new BorderDecorator(new JCheckBox('Decorated JCheckBox')); public Frame1() { try { this.setDefaultCloseOperation(EXIT_ON_CLOSE); getContentPane().setLayout(null); label1.setBounds(new Rectangle(10, 10, 120, 25)); this.getContentPane().add(label1, null); label2.setBounds(new Rectangle(10, 60, 120, 25)); this.getContentPane().add(label2, null); checkBox1.setBounds(new Rectangle(10, 110, 160, 25)); this.getContentPane().add(checkBox1, null); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Frame1 frame1 = new Frame1(); frame1.setBounds(0, 0, 200, 200); frame1.setVisible(true); }} ResizableDecorator类 ResizableDecorator是装饰者的另一种类型。它没有重载父类的paint方法;它增加一个按钮,当点击按钮的时候,它可以改变或恢复自身的大小。列表4显示了ResizableDecorator类的实现代码。 列表 4 -- the ResizableDecorator classpackage decorator;import javax.swing.*;import java.awt.Graphics;import java.awt.Color;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.Rectangle;public class ResizableDecorator extends JComponent { // decorated component protected JComponent child; private JButton button = new JButton(); boolean minimum = false; private Rectangle r; public ResizableDecorator(JComponent component) { child = component; this.setLayout(new BorderLayout()); this.add(child); child.setLayout(null); button.setBounds(0, 0, 8, 8); child.add(button); button.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { button_actionPerformed(e); } }); } void button_actionPerformed(ActionEvent e) { if (minimum) { this.setBounds(r); } else { r = this.getBounds(); this.setBounds(r.x, r.y, 8, 8); } minimum = !minimum; }} 需要注意的是,这个装饰者同样扩展自JComponent,它的构造函数也接受一个JComponent类型的参数。除了定义了一个child变量来引用这个被修饰的组件外,它也定义了一个类型为JButton的变量。构造函数代码的头三行实现的功能是:将被修饰的组件作为儿子组件增加到修饰者。child = component;this.setLayout(new BorderLayout());this.add(child); 将一个Jbutton组件作为子组件增加给被修饰的组件。这个子组件的布局为空。JButton组件的尺寸是8*8,它被增加到这个被修饰组件的左上角。child.setLayout(null);button.setBounds(0, 0, 8, 8);child.add(button); 最后,我们为JButton增加一个监听对象。button.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { button_actionPerformed(e); }}); 当被增加到一个容器的时候,这个使用ResizableDecorator修饰的组件会在它的左上角出现一个小按钮。小按钮被点击的时候,会执行button_actionPerformed方法里面的代码。首先,它检查变量minimum的值。这个布尔变量被用来标识装饰者是否处于最小化。最初,变量的值为false,这个时候else部分的代码将被执行。else { r = this.getBounds(); this.setBounds(r.x, r.y, 8, 8);} 它将当前的尺寸赋值给变量r,r是一个Rectangle类型并且将它的范围设置为8 * 8。然后对minimum取反。minimum = !minimum; 当按钮被第二次点击的时候,minimum的值变为true。这个时候,if语句块的代码将被执行。if (minimum) { this.setBounds(r);} 这段代码恢复修饰者尺寸大小。 图2显示了带有三个被修饰过的组件的JFrame。其实现代码如列表5。 IMG http://www.onjava.com/onjava/2003/02/05/graphics/figure2.png[/IMG] 图 2 – 三个用ResizableDecorator类修饰的组件 列表 5 -- using the ResizableDecorator classpackage decorator;import java.awt.*;import javax.swing.*;import java.awt.event.*;public class Frame2 extends JFrame { ResizableDecorator label1 = new ResizableDecorator(new JLabel(' Label1')); ResizableDecorator button1 = new ResizableDecorator(new JButton('Button')); BorderDecorator label2 = new BorderDecorator(new ResizableDecorator( new JLabel(' doubly decorated') )); public Frame2() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Frame2 frame = new Frame2(); frame.setBounds(0, 0, 200, 200); frame.setVisible(true); } private void jbInit() throws Exception { this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.getContentPane().setLayout(null); label1.setBounds(new Rectangle(10, 10, 120, 25)); label2.setBounds(new Rectangle(10, 60, 120, 25)); button1.setBounds(new Rectangle(10, 110, 120, 25)); this.getContentPane().add(label1, null); this.getContentPane().add(label2, null); this.getContentPane().add(button1, null); }} 你可以使用一个或多个修饰者来修饰一个Jcomponent对象。就像列表5中的label2一样。如果你需要使用多个修饰者,不妨考虑一下提供一个抽象类Decorator,所有的修饰者都从这个类继承。采用这种方式,你就可以把多个修饰着公用的代码放到抽象类中实现。 总结: 这片文章将子类化和Decorator模式进行了比较,给予了两个基于Swing的采用Decorator模式的例子。虽然,使用Decorator模式改变一个Swing组件的可视化外观很普遍,但是它的作用不仅仅是用来改变用户界面。 作者介绍:Budi Kurniawan is an IT consultant specializing in Internet and object-oriented programming, and has taught both Microsoft and Java technologiesmatrix开源技术经onjava授权翻译并发布.如果你对此文章有任何看法或建议,请到Matrix论坛发表您的意见.注明: 如果对matrix的翻译文章系列感兴趣,请点击oreilly和javaworld文章翻译计划查看详细情况您也可以点击-disneytiger查看翻译作者的详细信息. Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
上一条:使用Decorator模式(一)下一条:MVC和Observer
相关文章: