1. 程式人生 > >57 java編程思想——創建窗口和程序片 可視編程和Beans

57 java編程思想——創建窗口和程序片 可視編程和Beans

集合 何事 ets 集成 .html out oob 創建 pub

57.java編程思想——創建窗口和程序片 可視編程和Beans

我們已看到Java 對創建可重復使用的代碼片工作而言是多麽的有價值。“最大限度地可重復使用”的代碼單元擁有類,因為它包含一個緊密結合在一起的單元特性(字段)和單元動作(方法),它們可以直接經過混合或通過繼承被重復使用。

繼承和多形態性是面向對象編程的精華,但在大多數情況下當我們創建一個應用程序時,我們真正最想要的恰恰是我們最需要的組件。我們希望在我們的設計中設置這些部件就像電子工程師在電路板上創造集成電路塊一樣(在使用Java 的情況下,就是放到WEB 頁面上)。這似乎會成為加快這種“模塊集合”編制程序方法的發展。

“可視化編程”最早的成功——非常的成功——要歸功於微軟公司的Visual Basic(VB,可視化Basic語言),接下來的第二代是Borland 公司Delphi(一種客戶/服務器數據庫應用程序開發工具,也是JavaBeans 設計的主要靈感)。這些編程工具的組件的像征就是可視化,這是不容置疑的,因為它們通常展示一些類型的可視化組件,例如:一個按慣或一個TextField。事實上,可視化通常表現為組件可以非常精確地訪問運行中程序。因此可視化編程方法的一部分包含從一個調色盤從拖放一個組件並將它放置到我們的窗體中。應用程序創建工具像我們所做的一樣編寫程序代碼,該代碼將導致正在運行的程序中的組件被創建。

簡單地拖放組件到一個窗體中通常不足以構成一個完整的程序。一般情況下,我們需要改變組件的特性,例如組件的色彩,組件的文字,組件連結的數據庫,等等。特性可以參照屬性在編程時進行修改。我們可以在應用程序構建工具中巧妙處置我們組件的屬性,並且當我們創建程序時,構建數據被保存下來,所以當該程序被啟動時,數據能被重新恢復。

我們可能習慣於使用對象的多個特性,這也是一個動作集合。在設計時,可視化組件的動作可由事件部分地代表,意味著“任何事件都可以發生在組件上”。通常,由我們決定想發生的事件,當一個事件發生時,對所發生的事件連接代碼。

這是關鍵性的部分:應用程序構建工具可以動態地詢問組件(利用映象)以發現組件支持的事件和屬件。一旦它知道它們的狀態,應用程序構建工具就可以顯示組件的屬性並允許我們修改它們的屬性(當我們構建程序時,保存它們的狀態),並且也顯示這些事件。一般而言,我們做一些事件像雙擊一個事件以及應用程序構建工具創建一個代碼並連接到事件上。當事件發生時,我們不得不編寫執行代碼。應用程序構建工具累計為我們做了大量的工作。結果我們可以註意到程序看起來像它所假定的那樣運行,並且依賴應用程序構建工具去為我們管理連接的詳細資料。可視化的編程工具如此成功的原因是它們明顯加快構建的應用程序的處理過程——當然,用戶接口作為應用程序的一部分同樣的好。

1 什麽是B e a n

在經細節處理後,一個組件在類中被獨特的具體化,真正地成為一塊代碼。關鍵的爭議在於應用程序構建工具發現組件的屬性和事件能力。為了創建一個VB 組件,程序開發者不得不編寫正確的同時也是復雜煩瑣的代碼片,接下來由某些協議去展現它們的事件和屬性。Delphi 是第二代的可視化編程工具並且這種開發語言主動地圍繞可視化編程來設計因此它更容易去創建一個可視化組件。但是,Java 帶來了可視化的創作組件做為Java Beans 最高級的“裝備”,因為一個Bean 就是一個類。我們不必再為制造任何的Bean 而編寫一些特殊的代碼或者使用特殊的編程語言。事實上,我們唯一需要做的是略微地修改我們對我們方法命名的辦法。方法名通知應用程序構建工具是否是一個屬性,一個事件或是一個普通的方法。

在Java 的文件中,命名規則被錯誤地曲解為“設計範式”。這十分的不幸,因為設計範式惹來不少的麻煩。命名規則不是設計範式,它是相當的簡單:

(1) 因為屬性被命名為xxx,我們代表性的創建兩個方法:getXxx()和setXxx()。註意get或set 後的第一個字母小寫以產生屬性名。“get”和“set”方法產生同樣類型的自變量。“set”和“get”的屬性名和類型名之間沒有關系。

(2) 對於布爾邏輯型屬性,我們可以使用上面的“get”和“set”方法,但我們也可以用“is”代替“ get”。

(3) Bean 的普通方法不適合上面的命名規則,但它們是公用的。

對於事件,我們使用“listener (接收器)”方法。這種方法完全同我們看到過的方法相同:(addFooBarListener(FooBarListener)和removeFooBarListener(FooBarListener)方法用來處理FooBar事件。大多數時候內建的事件和接收器會滿足我們的需要,但我們可以創建自己的事件和接收器接口。

我們可能註意到的從Java 1.0 到Java 1.1 的改變的問題:一些方法的名字太過於短小,顯然改寫名字毫無意義。現在我們可以看到為了制造Bean 中的特殊的組件,大多數的這些修改不得不適合於“get”和“set”命名規則。

已經可以利用上面的這些指導方針去創建一個簡單的Bean:

1.1 代碼

import java.awt.*;

import java.awt.event.*;

class Spots {

}

public class Frog {

private intjumps;

private Color color;

private Spots spots;

private booleanjmpr;

public intgetJumps() {

return jumps;

}

public voidsetJumps(intnewJumps){

jumps = newJumps;

}

public Color getColor() {

return color;

}

public voidsetColor(Color newColor){

color = newColor;

}

public Spots getSpots() {

return spots;

}

public voidsetSpots(Spots newSpots){

spots = newSpots;

}

public booleanisJumper() {

return jmpr;

}

public voidsetJumper(booleanj) {

jmpr = j;

}

public voidaddActionListener(ActionListener l) {

// ...

}

public voidremoveActionListener(ActionListener l) {

// ...

}

public voidaddKeyListener(KeyListener l) {

// ...

}

public voidremoveKeyListener(KeyListener l) {

// ...

}

// An"ordinary" public method:

public voidcroak() {

System.out.println("Ribbet!");

}

} /// :~

首先,我們可看到Bean 就是一個類。通常,所有我們的字段會被作為專用,並且可以接近的唯一辦法是通過方法。緊接著的是命名規則,屬性是jump,color,jumper,spots(註意這些修改是在第一個字母在屬性名的情況下進行的)。雖然內部確定的名字同最早的三個例子的屬性名一樣,在jumper 中我們可以看到屬性名不會強迫我們使用任何特殊的內部可變的名字(或者,真的擁有一些內部的可變的屬性名)。

Bean 事件的句柄是ActionEvent和KeyEvent ,這是根據有關接收器的“add”和“remove”命名方法得出的。最後我們可以註意到普通的方法croak()一直是Bean 的一部分,僅僅是因為它是一個公共的方法,而不是因為它符合一些命名規則。

1.2 用I n t r o s p e c to r 提取B e a n I n f o

當我們拖放一個Bean 的調色板並將它放入到窗體中時,一個Bean 的最關鍵的部分的規則發生了。應用程序構建工具必須可以創建Bean(如果它是默認的構建器的話,它就可以做)然後,在此範圍外訪問Bean 的源代碼,提取所有的必要的信息以創立屬性表和事件處理器。

Java 1.1 版的映象允許一個匿名類的所有方法被發現。

這完美地解決了Bean 的難題而無需我們使用一些特殊的語言關鍵字像在其它的可視化編程語言中所需要的那樣。事實上,一個主要的原因是映象增加到Java 1.1 版中以支持Beans(盡管映象同樣支持對象串聯和遠程方法調用)。因為我們可能希望應用程序構建工具的開發者將不得不映象每個Bean 並且通過它們的方法搜索以找到Bean 的屬性和事件。

這當然是可能的,但是Java 的研制者們希望為每個使用它的用戶提供一個標準的接口,而不僅僅是使Bean更為簡單易用,不過他們也同樣提供了一個創建更復雜的Bean 的標準方法。這個接口就是Introspector類,在這個類中最重要的方法靜態的getBeanInfo()。我們通過一個類處理這個方法並且getBeanInfo()方法全面地對類進行查詢,返回一個我們可以進行詳細研究以發現其屬性、方法和事件的BeanInfo 對象。

通常我們不會留意這樣的一些事物——我們可能會使用我們大多數的現成的Bean,並且我們不需要了解所有的在底層運行的技術細節。我們會簡單地拖放我們的Bean 到我們窗體中,然後配置它們的屬性並且為事件編寫處理器。

1.3 代碼2

import java.beans.*;

import java.lang.reflect.*;

public class BeanDumper {

public staticvoiddump(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("====================");

}

}

// Dump theclass of your choice:

public staticvoidmain(String[] args){

if (args.length< 1) {

System.err.println("usage: \n"+ "BeanDumperfully.qualified.class");

System.exit(0);

}

Class c = null;

try {

c = Class.forName(args[0]);

} catch (ClassNotFoundException ex) {

System.err.println("Couldn‘t find "+ args[0]);

System.exit(0);

}

dump(c);

}

} /// :~

BeanDumper.dump()是一個可以做任何工作的方法。首先它試圖創建一個BeanInfo 對象,如果成功地調用BeanInfo 的方法,就產生關於屬性、方法和事件的信息。在Introspector.getBeanInfo()中,我們會註意到有一個另外的自變量。由它來通知Introspector 訪問繼承體系的地點。在這種情況下,它在分析所有對象方法前停下,因為我們對看到那些並不感興趣。

因為屬性,getPropertyDescriptors()返回一組的屬性描述符號。對於每個描述符號我們可以調用getPropertyType()方法徹底的通過屬性方法發現類的對象。這時,我們可以用getName()方法得到每個屬性的假名(從方法名中提取),getname()方法用getReadMethod()和getWriteMethod()完成讀和寫的操作。最後的兩個方法返回一個可以真正地用來調用在對象上調用相應的方法方法對象(這是映象的一部分)。對於公共方法(包括屬性方法),getMethodDescriptors( )返回一組方法描述字符。每一個我們都可以得到相當的方法對象並可以顯示出它們的名字。

對於事件而言,getEventSetDescriptors()返回一組事件描述字符。它們中的每一個都可以被查詢以找出接收器的類,接收器類的方法以及增加和刪除接收器的方法。BeanDumper 程序打印出所有的這些信息。

Introspector 在從我們的Bean 產生一個BeanInfo 對象時看到的大部分內容。我們可註意

到屬性的類型和它們的名字是相互獨立的。請註意小寫的屬性名。(當屬性名開頭在一行中有超過不止的大寫字母,這一次程序就不會被執行。)並且請記住我們在這裏所見到的方法名(例如讀和與方法)真正地從一個可以被用來在對象中調用相關方法的方法對象中產生。

通用方法列表包含了不相關的事件或者屬性,例如croak()。列表中所有的方法都是我們可以有計劃的為Bean 調用,並且應用程序構建工具可以選擇列出所有的方法,當我們調用方法時,減輕我們的任務。

最後,我們可以看到事件在接收器中完全地分析研究它的方法、增加和減少接收器的方法。基本上,一旦我們擁有BeanInfo ,我們就可以找出對Bean 來說任何重要的事物。我們同樣可以為Bean 調用方法,即使我們除了對象外沒有任何其它的信息(此外,這也是映象的特點)。

再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://www.cnblogs.com/captainbed

57 java編程思想——創建窗口和程序片 可視編程和Beans