1. 程式人生 > >57 java程式設計思想——建立視窗和程式片 可視程式設計和Beans

57 java程式設計思想——建立視窗和程式片 可視程式設計和Beans

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