Membangun perkumpulan kacang: Buat komponen JavaBeans yang dapat digunakan kembali

Dalam seri singkat ini, kami memeriksa perkembangan komponen perangkat lunak JavaBeans. Pada akhirnya, sebagian besar biji akan dimanipulasi dalam lingkungan pengembangan biji; namun, kami hanya mementingkan di sini dengan aspek kerangka kerja tingkat sumber. Keuntungan mengembangkan JavaBeans - yaitu, mengembangkan spesifikasi JavaBeans - ada beberapa manfaat, di antaranya:

  • Kacang dapat dengan mudah dimanipulasi dalam lingkungan pengembangan visual oleh pengguna yang tidak perlu terampil secara teknis dalam pengembangan Java tingkat sumber.

  • Karena antarmuka standar, biji kopi siap didistribusikan, yang memungkinkan komponen pihak ketiga lebih mudah diintegrasikan ke dalam upaya pengembangan.

  • Pengembang dapat dengan mudah mentransfer kode yang telah dikembangkan untuk satu proyek ke dalam pustaka komponen yang dapat digunakan kembali, yang dapat diakses dalam upaya pengembangan di masa mendatang.

Mata badai

Dalam

bagian pertama dari seri ini

, kami mengembangkan dua kacang sederhana: kacang alarm non-visual dan kacang panah kiri / kanan grafis. Keduanya ditambah dengan visual

customizer

dan

informasi kacang

kelas. Untuk info yang kami bahas bulan ini, kami tidak akan menyediakan penyesuai; sebagai gantinya, kita akan berkonsentrasi pada penggunaan biji dan komponen yang ada untuk membuat biji yang lebih besar dan lebih baik.

Prasyarat

Sebagai kelanjutan dari seri dua bagian, saya akan mengasumsikan keakraban dengan masalah yang dibahas dalam angsuran sebelumnya, termasuk artikel dan sumber tambahan.

Kacang

Dari awal hingga akhir seri ini, kami mengembangkan kacang berikut ini:

AlarmBean Kacang non-grafis yang menjalankan peristiwa setelah penundaan tertentu.
ArrowBean

Kacang grafik panah kiri / kanan.

ProgressBean

Kacang tampilan kemajuan grafis.

NumberFieldBean

TextFieldKacang numerik grafis dengan tombol gulung. Kacang ini memanfaatkan kacang ArrowBean.

FontChooserBean

Kacang pemilih font grafis. Kacang ini menggunakan kacang NumberFieldBean.

FontSelectorBean

Kacang pemilih font grafis yang menampilkan font saat ini dan menyediakan tombol OK / Batal. Kacang ini menggunakan kacang FontChooserBean.

FontDialogBean

Kacang pemilih font grafis yang muncul di pemilih font dalam dialog terpisah. Kacang ini menggunakan kacang FontSelectorBean.

Kami membahas kacang AlarmBeandan ArrowBeansecara rinci bulan lalu; di episode kali ini, kita akan membahas biji yang tersisa dengan berbagai tingkat detail.

Anda mungkin bertanya-tanya mengapa kami membuat tiga kacang font. Tujuan utamanya adalah hanya untuk menghasilkan kacang pemilih font yang memunculkan dialog font saat pengguna mengklik tombol. Tugas ini secara alami terbagi menjadi tiga kacang yang akan kami hasilkan: Yang pertama adalah antarmuka pengguna untuk pemilihan font, yang kedua menambahkan kontrol dialog dan sampel font, dan yang ketiga memperkenalkan tombol untuk memunculkan dialog dan berisi dasar kode penanganan dialog.

Tanpa kacang, kami harus mengembangkan item ini sebagai komponen AWT khusus atau sebagai kelas monolitik tunggal; menggunakan kacang, kita dapat mengembangkan tiga bagian sebagai kacang independen yang dapat digunakan kembali dengan sendirinya.

Ruang lingkup kami

Seperti angsuran pertama dari seri ini, kami hanya mementingkan beanisme dari kelas-kelas ini dan bukan mur dan baut sebenarnya yang membuat mereka berdetak. Sebagai hasilnya, kami akan membahas biji kopi dalam bentuk kerangka, menyoroti potongan-potongan yang memiliki relevansi khusus dengan warna merah, dan meninggalkan detail lainnya untuk Anda teliti di waktu luang. Kami juga tidak akan menyibukkan diri dengan penyesuai, yang kami bahas secara cukup rinci dengan diskusi kami tentang dua biji pertama.

Untuk melihat kerja paksa di balik kacang, lihat kode sumber lengkapnya.

Membangun kacang ProgressBean

ProgressBean

adalah kacang tampilan kemajuan sederhana. Ini adalah komponen AWT khusus yang menampilkan nilai persentase dan representasi grafik batang dari nilai ini, seperti yang ditunjukkan pada gambar di bawah ini. Ini memperlihatkan dua properti: nilai bar saat ini dan maksimum.

Nilai saat ini diekspos sebagai properti yang dapat diamati . Properti yang dapat diamati adalah properti yang perubahannya dapat diamati. Observer didaftarkan dengan bean dengan cara yang sama seperti event listener, dan mereka diberitahu setiap kali properti berubah. Sifat individu dari biji harus dibuat agar dapat diamati secara eksplisit oleh biji; tidak mungkin untuk mengamati perubahan pada sembarang properti dari kacang manapun.

Kacang ini diimplementasikan dengan dua kelas berikut:

  • ProgressBean - Kelas kacang utama

  • ProgressBeanBeanInfo - Kelas informasi kacang

Kelas ProgressBean

Itu

ProgressBean kelas adalah kelas kacang utama, komponen AWT kustom sederhana dan kacang Java.

kelas publik ProgressBean meluas Komponen ... 

This bean is a lightweight component, so we extend Component instead of Canvas, and provide an appropriate paint() method. The lightweight component framework is more efficient than the traditional custom-component framework, requiring fewer resources of the local windowing system. As a component, we automatically inherit the serializability mandated by JavaBeans, and we provide the default no-arg constructor.

public void setBarground (Color c) ... public Color getBarground () ... public synchronized void setMaximum (int m) ... public int getMaximum () ... 

Here, we expose the Color property barground (the color of the displayed bar) and the int property maximum (the maximum bar value).

public synchronized void setValue (int v) { if (value != v) { value = v; repaint (); fireValueChange (); } } public int getValue () ... 

The int property value is observable, which means that we must inform all interested listeners whenever its value changes. To this end, we call our fireValueChange() method to inform the listeners whenever setValue() is called.

protected PropertyChangeSupport listeners = new PropertyChangeSupport (this); public void addPropertyChangeListener (PropertyChangeListener l) { listeners.addPropertyChangeListener (l); } public void removePropertyChangeListener (PropertyChangeListener l) { listeners.removePropertyChangeListener (l); } 

Here, we maintain a list of objects that are registered to be notified whenever an observable property changes. We use the class PropertyChangeSupport from the java.beans package to maintain this list. The constructor for this class requires us to specify the bean that will be the origin of property change events; in this case, it is this, and the methods that it provides allow us to maintain the list.

By exposing the methods addPropertyChangeListener() and removePropertyChangeListener(), we automatically indicate that this bean has observable properties. We do not, however, indicate which properties are observable. That information must be appropriately documented with the bean.

protected Integer oValue = new Integer (nilai); dilindungi void fireValueChange () {listener.firePropertyChange ("value", oValue, oValue = new Integer (value)); }

Kami memanggil metode ini untuk memberi tahu pendengar tentang perubahan dalam properti nilai kami ; kami menggunakan firePropertyChange()metode daftar kami untuk menyebarkan pemberitahuan ini. Parameter pertama adalah nama properti, yang harus cocok dengan nama properti yang terekspos; parameter kedua adalah nilai lama properti; dan properti ketiga adalah nilai baru. The PropertyChangeSupportpengembalian kelas tanpa melakukan apa-apa jika nilai-nilai lama dan baru adalah sama.

Kelas ProgressBeanBeanInfo

Itu

ProgressBeanBeanInfoclass hanya mendeskripsikan ProgressBeanbean, mengaburkan informasi yang diwariskan yang ingin kita samarkan.

Membangun kacang NumberFieldBean

This bean implements a common user-interface component, the rollable number entry field -- a numeric text field that provides increment and decrement arrows, as shown in the figure below. This bean brings up an important JavaBeans concept:

programmatic manipulation of beans

.

Programmatic manipulation of beans refers to the mechanisms that JavaBeans provides for programmatically creating and accessing beans. Although it is possible to access beans using the standard Java object creation (new X ()) and type-casting mechanisms ((Y) x), it is recommended that you use the provided JavaBeans mechanisms to allow for future extension of the JavaBeans framework.

This bean is implemented with the following two classes:

  • NumberFieldBean -- The main bean class

  • NumberFieldBeanBeanInfo -- The bean information class

Class NumberFieldBean

The NumberFieldBean class, the main bean class, is an AWT container that adds three components: two ArrowBean beans and a TextField. Programmatic access to the ArrowBean class requires that we make use of the bean manipulation mechanisms I mentioned a moment ago.

The current numeric value is exposed as an observable property. Although it is a normal property that can be accessed and manipulated through the usual beans accessor methods, it is also observable, so listeners can register to be notified whenever its value changes. We do not fire an event when the user presses Return, although that would be an obvious extension to this class.

public class NumberFieldBean extends Container implements ActionListener ... 

We extend Container and implement ActionListener in order to receive events from the beans and AWT components that we use. Extending Container instead of the more traditional Panel means that this bean, like the ProgressBean bean is a lightweight component.

public NumberFieldBean () ... 

As a bean, we must provide a public no-arg constructor. Note that we should not provide other constructors for programmatic use; doing so would go against the JavaBeans access mechanism.

try { down = (ArrowBean) Beans.instantiate (getClass ().getClassLoader (), "org.merlin.beans.arrow.ArrowBean"); } catch (Exception ex) { ex.printStackTrace (); } 

Here, we create an ArrowBean using the programmatic beans instantiation mechanism. We don't use the standard Java new operator; instead, we use the instantiate() method of class Beans. We specify the ClassLoader to use for loading the bean class; in this case, we use our own ClassLoader and the fully qualified name of the bean class ("org.merlin.beans.arrow.ArrowBean"), and cast the resulting Object to the appropriate class.

Note that the instantiate() method may throw a variety of exceptions (for example, if the specified bean could not be located). We simply catch and display any such exceptions, which, by the way, should not occur if the bean is appropriately installed.

add ("East", (Component) Beans.getInstanceOf (down, Component.class)); 

Here, we cast the ArrowBean to a Component and add it as a normal Component. We don't use the standard (Component) type-casting mechanism, and we don't use the fact that our AlarmBean is a subclass of Component; instead, we use the getInstanceOf() method of class Beans. We specify the bean that we wish to cast and the Class object to which we wish to cast it (in this case, Component.class).

Although this approach makes little sense right now, future versions of JavaBeans will support beans composed of multiple class files, as well as beans that can expose different aspects of themselves as the different classes. For example, a bean could appear to subclass both Component and RemoteObject by providing two coupled classes: a Component and a RemoteObject. Using the JavaBeans type-casting mechanism, the appropriate bean object can be returned automatically, so beans can have apparent multiple-inheritance, although Java does not natively support this. For details, see the "Glasgow" JavaBeans specification. (A link to this spec is provided in the Resources section of this article.)

It is necessary for us to use these beans access mechanisms now, so we can transition our beans to future JavaBeans technologies without any problems.

down.setDirection (ArrowBean.LEFT); down.addActionListener (this); 

Here, we configure the ArrowBean using the setDirection() property accessor and the addActionListener() registration method. We can use these property accessors and listener registration methods directly on the bean we just created; it is only necessary to use the JavaBeans type-casting feature when we are accessing an aspect of a bean that is inherited from another class.

public synchronized void setValue (int v) { field.setText (String.valueOf (v)); fireValueChange (getValue ()); } public synchronized int getValue () ... 

Here, we expose the int property value, which is the value of this field. This property is observable, so we must notify listeners whenever it is changed. We do this by calling our fireValueChange() method.

public void setColumns (int c) ... public int getColumns () ... public synchronized void setMinimum (int m) ... public int getMinimum () ... public synchronized void setMaximum (int m) ... public int getMaximum () ... public synchronized void setStep (int s) ... public int getStep () ... 

Di sini, kami mengekspos kolomint properti , minimum , maksimum , dan langkah , yang masing-masing, jumlah kolom yang ditampilkan di , nilai minimum dan maksimum yang harus dipegang bidang ini, dan jumlah yang harus diubah oleh tombol panah nilai. Properti ini tidak dapat diamati.TextField

Perhatikan bahwa kami menggunakan sinkronisasi untuk memastikan keamanan utas jika sesuai.

publik disinkronkan void actionPerformed (ActionEvent e) {int value = getValue (); if (e.getSource () == down) {if (value> minimum) {value = (value - step> value)? minimum: penjepit (nilai - langkah); setValue (nilai); }} ...