Java编程思想第4版[中文版](PDF格式)-第114部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
filename。setText(saveFile);
directory。setText(d。getDirectory());
} else {
filename。setText(〃You pressed cancel〃);
directory。setText(〃〃);
}
}
}
public static void main(String'' args) {
Frame f = new FileDialogNew();
f。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
f。setSize(250;110);
f。setVisible(true);
}
} ///:~
如果所有的改变是这样的容易那将有多棒,但至少它们已足够容易,并且我们的代码已受益于这改进的可读
性上。
13。16。5 动态绑定事件
新AWT 事件模型给我们带来的一个好处就是灵活性。在老的模型中我们被迫为我们的程序动作艰难地编写代
码。但新的模型我们可以用单一方法调用增加和删除事件动作。下面的例子证明了这一点:
//: DynamicEvents。java
// The new Java 1。1 event model allows you to
// change event behavior dynamically。 Also
// demonstrates multiple actions for an event。
import java。awt。*;
import java。awt。event。*;
import java。util。*;
public class DynamicEvents extends Frame {
Vector v = new Vector();
int i = 0;
Button
b1 = new Button(〃Button 1〃);
b2 = new Button(〃Button 2〃);
public DynamicEvents() {
setLayout(new FlowLayout());
b1。addActionListener(new B());
b1。addActionListener(new B1());
b2。addActionListener(new B());
b2。addActionListener(new B2());
431
…………………………………………………………Page 433……………………………………………………………
add(b1);
add(b2);
}
class B implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃A button was pressed〃);
}
}
class CountListener implements ActionListener {
int index;
public CountListener(int i) { index = i; }
public void actionPerformed(ActionEvent e) {
System。out。println(
〃Counted Listener 〃 + index);
}
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃Button 1 pressed〃);
ActionListener a = new CountListener(i++);
v。addElement(a);
b2。addActionListener(a);
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃Button 2 pressed〃);
int end = v。size() …1;
if(end 》= 0) {
b2。removeActionListener(
(ActionListener)v。elementAt(end));
v。removeElementAt(end);
}
}
}
public static void main(String'' args) {
Frame f = new DynamicEvents();
f。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e){
System。exit(0);
}
});
f。setSize(300;200);
f。show();
}
} ///:~
这个例子采取的新手法包括:
(1) 在每个按钮上附着不少于一个的接收器。通常,组件把事件作为多造型处理,这意味着我们可以为单个
事件注册许多接收器。当在特殊的组件中一个事件作为单一造型被处理时,我们会得到
TooManyListenersException (即太多接收器异常)。
432
…………………………………………………………Page 434……………………………………………………………
(2) 程序执行期间,接收器动态地被从按钮B2 中增加和删除。增加用我们前面见到过的方法完成,但每个组
件同样有一个removeXXXListener() (删除XXX 接收器)方法来删除各种类型的接收器。
这种灵活性为我们的编程提供了更强大的能力。
我们注意到事件接收器不能保证在命令他们被增加时可被调用(虽然事实上大部分的执行工作都是用这种方
法完成的)。
13。16。6 将事务逻辑与 UI 逻辑区分开
一般而言,我们需要设计我们的类如此以至于每一类做“一件事”。当涉及用户接口代码时就更显得尤为重
要,因为它很容易地封装“您要做什么”和“怎样显示它”。这种有效的配合防止了代码的重复使用。更不
用说它令人满意的从GUI 中区分出我们的“事物逻辑”。使用这种方法,我们可以不仅仅更容易地重复使用
事物逻辑,它同样可以更容易地重复使用 GUI。
其它的争议是“动作对象”存在的完成分离机器的多层次系统。动作主要的定位规则允许所有新事件修改后
立刻生效,并且这是如此一个引人注目的设置系统的方法。但是这些动作对象可以被在一些不同的应用程序
使用并且因此不会被一些特殊的显示模式所约束。它们会合理地执行动作操作并且没有多余的事件。
下面的例子演示了从GUI 代码中多么地轻松的区分事物逻辑:
//: Separation。java
// Separating GUI logic and business objects
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
class BusinessLogic {
private int modifier;
BusinessLogic(int mod) {
modifier = mod;
}
public void setModifier(int mod) {
modifier = mod;
}
public int getModifier() {
return modifier;
}
// Some business operations:
public int calculation1(int arg) {
return arg * modifier;
}
public int calculation2(int arg) {
return arg + modifier;
}
}
public class Separation extends Applet {
TextField
t = new TextField(20);
mod = new TextField(20);
BusinessLogic bl = new BusinessLogic(2);
Button
calc1 = new Button(〃Calculation 1〃);
calc2 = new Button(〃Calculation 2〃);
public void init() {
433
…………………………………………………………Page 435……………………………………………………………
add(t);
calc1。addActionListener(new Calc1L());
calc2。addActionListener(new Calc2L());
add(calc1); add(ca lc2);
mod。addTextListener(new ModL());
add(new Label(〃Modifier:〃));
add(mod);
}
static int getValue(TextField tf) {
try {
return Integer。parseInt(tf。getText());
} catch(NumberFormatException e) {
return 0;
}
}
class Calc1L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t。setText(Integer。toString(
bl。calculation1(getValue(t))));
}
}
class Calc2L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t。setText(Integer。toString(
bl。calculation2(getValue(t))));
}
}
class ModL implements TextListener {
public void textValueChanged(TextEvent e) {
bl。setModifier(getValue(mod));
}
}
public static void main(String'' args) {
Separation applet = new Separation();
Frame aFrame = new Frame(〃Separation〃);
aFrame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
aFrame。add(applet; BorderLayout。CENTER);
aFrame。setSize(200;200);
applet。init();
applet。start();
aFrame。setVisible(true);
}
} ///:~
可以看到,事物逻辑是一个直接完成它的操作而不需要提示并且可以在GUI 环境下使用的类。它正适合它的
工作。区分动作记录了所有UI 的详细资料,并且它只通过它的公共接口与事物逻辑交流。所有的操作围绕中
心通过UI 和事物逻辑对象来回获取信息。因此区分,轮流做它的工作。因为区分中只知道它同事物逻辑对象
434
…………………………………………………………Page 436……………………………………………………………
对话(也就是说,它没有高度的结合),它可以被强迫同其它类型的对象对话而没有更多的烦恼。
思考从事物逻辑中区分 UI 的条件,同样思考当我们调整传统的Java 代码使它运行时,怎样使它更易存活。
13。16。7 推荐编码方法
内部类是新的事件模型,并且事实上旧的事件模型连同新库的特征都被它好的支持,依赖老式的编程方法无
疑增加了一个新的混乱的因素。现在有更多不同的方法为我们编写讨厌的代码。凑巧的是,这种代码显现在
本书中和程序样本中,并且甚至在文件和程序样本中同SUN 公司区别开来。在这一节中,我们将看到一些关
于我们会和不会运行新 AWT 的争执,并由向我们展示除了可以原谅的情况,我们可以随时使用接收器类去解
决我们的事件处理需要来结束。因为这种方法同样是最简单和最清晰的方法,它将会对我们学习它构成有效
的帮助。
在看到任何事以前,我们知道尽管 Java 1。1 向后兼容Java 1。0 (也就是说,我们可以在1。1 中编译和运行
1。0 的程序),但我们并不能在同一个程序里混合事件模型。换言之,当我们试图集成老的代码到一个新的
程序中时,我们不能使用老式的action()方法在同一个程序中,因此我们必须决定是否对新程序使用老的,
难以维护的方法或者升级老的代码。这不会有太多的竞争因为新的方法对老的方法而言是如此的优秀。
1。 准则:运行它的好方法
为了给我们一些事物来进行比较,这儿有一个程序例子演示向我们推荐的方法。到现在它会变得相当的熟悉
和舒适。
//: GoodIdea。java
// The best way to design classes using the new
// Java 1。1 event model: use an inner class for
// each different event。 This maximizes
// flexibility and modularity。
import java。awt。*;
import java。awt。event。*;
import java。util。*;
public class GoodIdea extends Frame {
Button
b1 = new Button(〃Button 1〃);
b2 = new Button(〃Button 2〃);
public GoodIdea() {
setLayout(new FlowLayout());
b1。addActionListener(new B1L());
b2。addActionListener(new B2L());
add(b1);
add (b2);
}
public class B1L implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃Button 1 pressed〃);
}
}
public class B2L implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃Button 2 pressed〃);
}
}
public static void main(String'' args) {
Frame f = new GoodIdea();
f。addWindowListener(