`
fly.net.cn
  • 浏览: 187776 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java设计模式之策略模式(2)

阅读更多

策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的基本原则:封装变化的概念;编程中使用接口,而不是对接口实现。策略模式的定义如下:

定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。

策略模式使开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间是弱连接的关系。弱连接的特性使软件具有更强的可扩展性,易于维护;更重要的是,它大大提高了软件的可重用性。

为了说明策略模式,我们将首先讨论一下在Swing中是如何利用策略模式来绘制组件边界的,然后讨论在Swing中使用策略模式带来的好处,最后讨论如何在软件中实现策略模式。

Swing边框

对所有的Swing组件,例如按钮、列表单等,都还可以绘制边框。在Swing中提供了各种 边框类型,例如bevel、etched、line、titled等。Swing组件的边框是通过JComponent类来绘制的,该类是所有Swing 组件的基类,实现了所有Swing组件公共的功能。在JComponent中有一个paintBorder()方法,该方法为组件绘制边框。Swing的 开发人员可以象下面的例子中所示那样来绘制边框:

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>// 一段实现paintBorder()方法代码
protected void paintBorder(Graphics g) {
switch(getBorderType()) {
case LINE_BORDER: paintLineBorder(g);
break;
case ETCHED_BORDER: paintEtchedBorder(g);
break;
case TITLED_BORDER: paintTitledBorder(g);
break;
...
}
}

请注意上面的代码只是一种假设,事实上Swing的开发人员并没有这样实现 paintBorder()方法。在上面的代码中,在JComponent中绘制边框的代码被直接写入了paintBorder()方法中,这意味着 JComponent和绘制边框的功能被紧密地结合在了一起。很自然地大家会联想到如果需要实现一种新的边框类型,开发人员必须修改至少三处代码:首先增 加一个常量,该常量代表新添加的边框的类型值;其次需要在Switch语句中增加一个case语句;最后开发人员需要实现paintXXXBorder ()方法,其中XXX代表新边框的名称。

很显然要扩展上面paintBorder()方法的功能是一件很困难的事情,不仅 仅是因为开发人员需要增加一种新的边框类型,更麻烦的是开发人员很难修改JComponent类。JComponent类已经被编译到了Swing的开发 工具中,如果开发人员想修改它的话,必须获得Swing的源代码,修改后重新编译Swing。同时在用户的计算机上与需要使用新编译的Swing API。另外所有的Swing组件都可以使用开发人员新添加的边框类型。有可能开发人员只希望新的边框被某些组件使用,但是现在开发人员无法对使用该边框 的组件进行限制。

开发人员有更好的实现方法吗?答案就是策略模式。通过策略模式,可以将 JComponent和实现绘制边框的代码分离开来,这样开发人员在增加或修改绘制边框的代码使就不需要修改JComponent的代码。通过应用策略模 式,开发人员将变化的概念(在这个例子中是绘制边框)封装起来,然后通过一个Border接口,使程序能够重用绘制边框的功能。下面让我们来看 JComponent是如何利用策略模式来实现绘制边框的功能的:

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>// Swing中paintBorder()方法的源代码
protected void paintBorder(Graphics g) {
Border border = getBorder();
if (border != null) {
border.paintBorder(this, g, 0, 0, getWidth(), getHeight());
}
}

上面的paintBorder()方法通过一个border对象绘制了组件的边框。 这样border对象替代了前一个例子中的JComponent封装了边框绘制的功能。我们还应该注意到JComponent将一个对自己的引用传递给了 Border.paintBorder()方法,这是因为Border的实例必须知道它对应的组件的信息,这种方式通常被称为委托。通过这种方式,一个对 象可以将功能委托给另一个对象来实现。

在JComponent类中引用了一个Border对象,通过JComponent.getBorder()方法可以获得该Border对象。下面的代码演示了如何设定和获得Border对象:

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>...
private Border border;
...
public void setBorder(Border border) {
Border oldBorder = this.border;
this.border = border;
firePropertyChange("border", oldBorder, border);
if (border != oldBorder) {
if (border == null || oldBorder == null || !(border.getBorderInsets(this).
equals(oldBorder.getBorderInsets(this)))) {
revalidate();
}
repaint();
}
}
...
public Border getBorder() {
return border;
}

当开发人员通过JComponent.setBorder()方法设定了一个组件的 边框后,JComponent类发出一个属性更新事件。如果新的边框和以前的边框不同的话,setBorder()方法就重新绘制边框。 getBorder()方法仅仅返回对Border对象的引用。图1显示了Border的类结构图:

图1 Border的类结构图

通过类结构图我们可以看到,JComponent类中保存了一个对Border对象的引用。由于Border是一个接口,Swing组件可以使用任何一个实现了Border接口的类。

现在我们已经知道了JComponent是如何利用策略模式来绘制组件的边框的。下面让我们通过实现一个新的边框类型来测试一下它的可扩展性。

实现一个新的边框类型

图2中是一个有三个JPanel对象的小程序,每个JPanel对象有各自不同的边框,每个边框对应一个HandleBorder实例。

图2 新的边框类型

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>// HandleBorder.java
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class HandleBorder extends AbstractBorder {
protected Color lineColor;
protected int thick;
public HandleBorder() {
this(Color.black, 6);
}
public HandleBorder(Color lineColor, int thick) {
this.lineColor = lineColor;
this.thick = thick;
}
public void paintBorder(Component component,
Graphics g, int x, int y, int w, int h) {
Graphics copy = g.create();
if(copy != null) {
try {
copy.translate(x,y);
paintRectangle(component,copy,w,h);
paintHandles(component,copy,w,h);
}
finally {
copy.dispose();
}
}
}
public Insets getBorderInsets() {
return new Insets(thick,thick,thick,thick);
}
protected void paintRectangle(Component c, Graphics g,
int w, int h) {
g.setColor(lineColor);
g.drawRect(thick/2,thick/2,w-thick-1,h-thick-1);
}
protected void paintHandles(Component c, Graphics g,
int w, int h) {
g.setColor(lineColor);
g.fillRect(0,0,thick,thick);
g.fillRect(w-thick,0,thick,thick);
g.fillRect(0,h-thick,thick,thick);
g.fillRect(w-thick,h-thick,thick,thick);
g.fillRect(w/2-thick/2,0,thick,thick);
g.fillRect(0,h/2-thick/2,thick,thick);
g.fillRect(w/2-thick/2,h-thick,thick,thick);
g.fillRect(w-thick,h/2-thick/2,thick,thick);
}
}

HandleBorder类继承了 javax.swing.border.AbstractBorder类并重写了paintBorder()和getBorderInsets()。 HandleBorder是如何实现的其实并不重要,重要的是由于Swing使用了策略模型,开发人员能够很方便地增加新的边框类型。下面的代码显示了如 何使用HandleBorder类。在这个例子中创建了三个JPanel对象,并对每个JPanel对象设定一个HandleBorder实例作为边框。

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>// Test.java
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JFrame {
public static void main(String[] args) {
JFrame frame = new Test();
frame.setBounds(100, 100, 500, 200);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.show();
}
public Test() {
super("实现一个新的边框类型");
Container contentPane = getContentPane();
JPanel[] panels = { new JPanel(),
new JPanel(), new JPanel() };
Border[] borders = { new HandleBorder(),
new HandleBorder(Color.red, 8),
new HandleBorder(Color.blue, 10) };
contentPane.setLayout(
new FlowLayout(FlowLayout.CENTER,20,20));
for(int i=0; i < panels.length; ++i) {
panels[i].setPreferredSize(new Dimension(100,100));
panels[i].setBorder(borders[i]);
contentPane.add(panels[i]);
}
}
}

还记得在上面的例子中曾提到在有些情况下,对组件的引用会作为参数传递给 Border.paintBorder()方法。虽然上面的HandleBorder类没有保存对组件的引用,但是有些情况下Border接口的实现类会 使用到对组件的引用并从中获得关于组件的信息。例如在EtchedBorder中,paintBorder()方法通过对组件的引用获得它对应的组件的阴 影和高光色:

<ccid_nobr></ccid_nobr>

<ccid_code></ccid_code>// 下面的代码截取自javax.swing.border.EtchedBorder
public void paintBorder(Component component, Graphics g, int x, int y,
int width, int height) {
int w = width;
int h = height;
g.translate(x, y);
g.setColor(etchType == LOWERED? getShadowColor(component) :
getHighlightColor(component));
g.drawRect(0, 0, w-2, h-2);
g.setColor(etchType == LOWERED? getHighlightColor(component) :
getShadowColor(component));
g.drawLine(1, h-3, 1, 1);
g.drawLine(1, 1, w-3, 1);
g.drawLine(0, h-1, w-1, h-1);
g.drawLine(w-1, h-1, w-1, 0);
g.translate(-x, -y);
}

如何实现策略模型

通过以下步骤,开发人员可以很容易地在软件中实现策略模型:

1.对策略对象定义一个公共接口。

2.编写策略类,该类实现了上面的公共接口。

3.在使用策略对象的类中保存一个对策略对象的引用。

4.在使用策略对象的类中,实现对策略对象的set和get方法。

在Swing边框的例子中,公共接口是javax.swing.Border。策略类是LineBorder、EtchedBorder、HandleBorder等。而使用策略对象的类是JComponent。

分享到:
评论
1 楼 xingchen 2007-08-18  
说的很明白阿,多谢

相关推荐

    55-Java设计模式之策略模式与状态模式1

    Java 设计模式之策略模式与状态模式 策略模式是 Java 中的一种设计模式,它主要用于解决系统与第三方接口进行数据交互的问题。当系统需要与多种格式的数据进行交互时,使用策略模式可以很好地解决这个问题。例如,...

    Java 经典设计模式讲解以及项目实战

    Java 经典设计模式讲解以及项目实战 设计模式简介:主要介绍各种设计模式的概念和运用场景等 设计模式综合运用:主要是笔者在实际工作中运用到的一些设计模式综合运用事例的提炼 Spring设计模式简介:主要是讲述...

    Java 设计模式 策略模式

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在Java中,策略模式主要通过定义一系列的算法,并将每一个算法封装起来,使它们可以互相替换,让算法独立于使用它的客户而变化。 首先,策略模式的...

    java设计模式之策略模式与模板模式

    在Java编程领域,设计模式是解决常见问题的可重用解决方案,它们代表了软件设计的最佳实践。本篇文章将深入探讨两种重要的设计模式:策略模式和模板模式。通过理解这两种模式,开发者可以更好地组织代码,提高代码的...

    java设计模式-策略模式

    在这个“java设计模式-策略模式”的示例中,我们将深入探讨如何使用策略模式来实现一个简单的超市促销系统。 策略模式的核心思想是定义一系列的算法,并将每一个算法封装起来,使它们可以互相替换。这使得算法的...

    设计模式之策略模式Java实现和类设计图

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在Java中,策略模式通常涉及定义一系列算法,将每个算法封装到具有共同接口的独立类中,使得它们可以相互替换。这样做的主要好处是算法的变化不会影响...

    Java设计模式之策略模式

    **策略模式**是Java设计模式中的行为模式之一,它的核心思想是定义一系列的算法,并将每一个算法封装起来,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户。在Java编程中,策略模式常用于处理那些...

    JAVA设计模式(java设计)

    Java设计模式是面向对象编程领域中的重要概念,它是一套被广泛接受并实践的解决软件设计问题的经验总结。设计模式并非具体的代码或库,而是一种在特定情境下为了解决常见问题而制定的通用解决方案的描述。它们描述了...

    java设计模式之策略模式

    java设计模式之策略模式,详细的描述了策略模式的特征和思路

    Java设计模式之禅

    《Java设计模式之禅》是一本深入浅出讲解设计模式的书籍,书中不仅包含23种经典设计模式的案例,还详细介绍了设计模式背后的思想和原则,适合初学者以及对设计模式有一定了解的程序员阅读。本书旨在帮助读者理解如何...

    JAVA设计模式例程-策略模式

    在这个“JAVA设计模式例程-策略模式”的压缩包中,我们可以深入探讨策略模式的原理及其应用。 策略模式的核心思想是定义一系列算法,并将每一个算法封装起来,使它们可以相互替换。策略对象的使用让算法的变化独立...

    Java设计模式 设计模式介绍

    2、爪哇语言抽象工厂创立性模式介绍 3、工厂方法创立性模式介绍 4、单态创立性模式介绍 5、单态创立性模式介绍 6、观察者模式介绍7、责任链模式 8、设计模式之Observer 9、设计模式之Strategy(策略) 10、设计模式之...

    JAVA设计模式demo之策略模式

    在这个"JAVA设计模式demo之策略模式"的示例中,你可能会看到以下的代码结构: 1. **策略接口**:`Strategy.java` ```java public interface Strategy { void execute(); } ``` 这个接口定义了一个通用的行为...

    《java设计模式》课后习题模拟试题解答——刘伟.zip

    Java设计模式是软件工程中的一种最佳实践,它总结了在特定场景下解决常见问题的经验,为程序员提供了可重用的解决方案。本资料“《java设计模式》课后习题模拟试题解答——刘伟.zip”主要涵盖了Java设计模式的学习与...

    《Java设计模式》课后答案-刘伟.rar

    《Java设计模式》是刘伟教授的一本关于设计模式的教材,主要面向高等学校的学生和对Java编程有深入兴趣的开发者。设计模式是软件工程中的一种重要思想,它封装了在特定场景下的问题解决方案,可以提高代码的可读性、...

    JAVA设计模式chm文档

    创建模式: 设计模式之Factory 设计模式之Prototype(原型) 设计模式之Builder 设计模式之Singleton(单态) ...设计模式之Strategy(策略) 设计模式之Mediator(中介者) 设计模式之Interpreter(解释器) 设计模式之Visitor

Global site tag (gtag.js) - Google Analytics