繼承和多形態性是面向對象編程的精華,但在大多數情況下當我們創建一個應用程序時,我們真正最想要的 恰恰是我們最需要的組件。我們希望在我們的設計中設置這些部件就像電子工程師在電路板上創造集成電路 塊一樣(在使用Java 的情況下,就是放到WEB頁面上)。這似乎會成爲加快這種“模塊集合”編制程序方法 的發展。
可視化的編程工具如此成功的原因是它們明顯加快構建的應用程序的處理 過程——當然,用戶接口作爲應用程序的一部分同樣的好。
1. 什麼是 Bean
在Java 的文件中,命名規則被錯誤地曲解爲“設計範式”。這十分的不幸,因爲設計範式(參見第 16章) 惹來不少的麻煩。命名規則不是設計範式,它是相當的簡單:
(1) 因爲屬性被命名爲 xxx,我們代表性的創建兩個方法:getXxx()和 setXxx()。注意 get或 set後的第一 個字母小寫以產生屬 性名。“get”和“set”方法產生同樣類型的自變量。“set”和“get”的屬性名和類 型名之間沒有關係。
(2) 對於布爾邏輯型屬性,我們可以使用上面的“get”和“set”方法,但我們也可以用“is”代替 “ get”。
(3) Bean 的普通方法不適合上面的命名規則,但它們是公用的。
(4) 對於事件,我們使用“listener(接收器)”方法。這種方法完全同我們看到過的方法相同。
【案例1】一個簡單的java bean 程序
package jbean;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
class Spots
{
}
public class Frog
{
private int jumps;
private Color color;
private Spots spots;
private boolean jmpr;
public int getJumps()
{
return jumps;
}
public void setJumps(int newJumps)
{
jumps = newJumps;
}
public Color getColor()
{
return color;
}
public void setColor(Color newColor)
{
color = newColor;
}
public Spots getSpots()
{
return spots;
}
public void setSpots(Spots newSpots)
{
spots = newSpots;
}
public boolean isJumper()
{
return jmpr;
}
public void setJumper(boolean j)
{
jmpr = j;
}
public void addActionListener(ActionListener l)
{
}
public void removeActionListener(ActionListener l)
{
}
public void addKeyListener(KeyListener l)
{
}
public void removeKeyListener(KeyListener l)
{
}
public void croak()
{
System.out.println("Ribbet!");
}
}
我們可看到 Bean 就是一個類。通常,所有我們的字段會被作爲專用,並且可以接近的唯一辦法是通過 方法。緊接着的是命名規則,屬性是jump,color,jumper,spots(注意這些修改是在第一個字母在屬性名 的情況下進行的)。雖然內部確定的名字同最早的三個例子的屬性名一樣,在jumper中我們可以看到屬性名 不會強迫我們使用任何特殊的內部可變的名字(或者,真的擁有一些內部的可變的屬性名)。 Bean 事件的句柄是ActionEvent 和KeyEvent,這是根據有關接收器的“add”和“remove”命名方法得出 的。最後我們可以注意到普通的方法croak()一直是 Bean 的一部分,僅僅是因爲它是一個公共的方法,而不 是因爲它符合一些命名規則。
2. 用Introspector提取BeanInfo
【案例】獲取bean信息
package awt.test;
import java.beans.*;
import java.lang.reflect.*;
public class BeanDumper
{
public static void dump(Class bean)
{
BeanInfo bi = null;
try
{
bi = Introspector.getBeanInfo(bean, java.lang.Object.class);
} catch (IntrospectionException ex)
{
System.out.println("Couldn't introspect " + bean.getName());
System.exit(1);
}
PropertyDescriptor[] properties = bi.getPropertyDescriptors();
for (int i = 0; i < properties.length; i++)
{
Class p = properties[i].getPropertyType();
System.out.println("Property type:\n " + p.getName());
System.out.println("Property name:\n " + properties[i].getName());
Method readMethod = properties[i].getReadMethod();
if (readMethod != null)
System.out.println("Read method:\n " + readMethod.toString());
Method writeMethod = properties[i].getWriteMethod();
if (writeMethod != null)
System.out
.println("Write method:\n " + writeMethod.toString());
System.out.println("====================");
}
System.out.println("Public methods:");
MethodDescriptor[] methods = bi.getMethodDescriptors();
for (int i = 0; i < methods.length; i++)
System.out.println(methods[i].getMethod().toString());
System.out.println("======================");
System.out.println("Event support:");
EventSetDescriptor[] events = bi.getEventSetDescriptors();
for (int i = 0; i < events.length; i++)
{
System.out.println("Listener type:\n "
+ events[i].getListenerType().getName());
Method[] lm = events[i].getListenerMethods();
for (int j = 0; j < lm.length; j++)
System.out.println("Listener method:\n " + lm[j].getName());
MethodDescriptor[] lmd = events[i].getListenerMethodDescriptors();
for (int j = 0; j < lmd.length; j++)
System.out.println("Method descriptor:\n "
+ lmd[j].getMethod().toString());
Method addListener = events[i].getAddListenerMethod();
System.out.println("Add Listener Method:\n "
+ addListener.toString());
Method removeListener = events[i].getRemoveListenerMethod();
System.out.println("Remove Listener Method:\n "
+ removeListener.toString());
System.out.println("====================");
}
}
public static void main(String[] args)
{
Class c = null;
try
{
c = Class.forName("awt.test.Person");
} catch (ClassNotFoundException ex)
{
System.err.println("Couldn't find " + args[0]);
System.exit(0);
}
dump(c);
}
}
其中用來測試的Java Bean ,Person類
package awt.test;
import java.io.Serializable;
public class Person implements Serializable
{
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public Person()
{
super();
}
public Person(String name, int age)
{
super();
this.name = name;
this.age = age;
}
public void show(String a, int b)
{
System.out.println("show( )");
}
}
這裏面感覺就是用introspector這個取獲取bean裏面的屬性,其中屬性包括屬性的類型,屬性名。 bean裏面的方法,其中方法包括方法的各個屬性,以及bean裏面的方法以及bean裏面的事件。
3. 一個更復雜的Bean
package awt.test;
import java.awt.Canvas;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
public class BangBean extends Canvas implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
protected int xm;
protected int ym;
protected int cSize = 20;
protected String text = "Bang!";
protected int fontSize = 48;
protected Color tColor = Color.red;
protected ActionListener actionListener;
public BangBean()
{
addMouseListener(new ML());
addMouseMotionListener(new MML());
}
public int getCircleSize()
{
return cSize;
}
public void setCircleSize(int newSize)
{
cSize = newSize;
}
public String getBangText()
{
return text;
}
public void setBangText(String newText)
{
text = newText;
}
public int getFontSize()
{
return fontSize;
}
public void setFontSize(int newSize)
{
fontSize = newSize;
}
public Color getTextColor()
{
return tColor;
}
public void setTextColor(Color newColor)
{
tColor = newColor;
}
public void paint(Graphics g)
{
g.setColor(Color.black);
g.drawOval(xm - cSize / 2, ym - cSize / 2, cSize, cSize);
}
public void addActionListener(ActionListener l)
throws TooManyListenersException
{
if (actionListener != null)
throw new TooManyListenersException();
actionListener = l;
}
public void removeActionListener(ActionListener l)
{
actionListener = null;
}
class ML extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
Graphics g = getGraphics();
g.setColor(tColor);
g.setFont(new Font("TimesRoman", Font.BOLD, fontSize));
int width = g.getFontMetrics().stringWidth(text);
g.drawString(text, (getSize().width - width) / 2,
getSize().height / 2);
g.dispose();
if (actionListener != null)
actionListener.actionPerformed(new ActionEvent(BangBean.this,
ActionEvent.ACTION_PERFORMED, null));
}
}
class MML extends MouseMotionAdapter
{
public void mouseMoved(MouseEvent e)
{
xm = e.getX();
ym = e.getY();
repaint();
}
}
static class BBL implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("BangBean action");
}
}
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}
public static void main(String[] args)
{
BangBean bb = new BangBean();
try
{
bb.addActionListener(new BBL());
} catch (TooManyListenersException e)
{
}
Frame aFrame = new Frame("BangBean Test");
aFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
aFrame.add(bb, BorderLayout.CENTER);
aFrame.setSize(300, 300);
aFrame.setVisible(true);
}
}