Membangun biji kacang: Buat komponen JavaBeans yang dapat digunakan kembali

Dalam siri pendek ini, kami meneliti pengembangan komponen perisian JavaBeans. Pada akhirnya, kebanyakan kacang akan dimanipulasi dalam persekitaran pengembangan kacang; namun, kami hanya mementingkan aspek kerangka sumber tahap. Kelebihan mengembangkan JavaBeans - yaitu, berkembang sesuai dengan spesifikasi JavaBeans - beberapa kali lipat, di antaranya:

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

  • Kerana antara muka standard, kacang mudah diedarkan, yang membolehkan komponen pihak ketiga lebih mudah disatukan ke dalam usaha pembangunan.

  • Pembangun dapat dengan mudah memindahkan kod yang telah dikembangkan untuk satu projek ke perpustakaan komponen yang dapat digunakan kembali, yang dapat diakses dalam upaya pengembangan di masa depan.

Mata ribut

Di dalam

bahagian pertama siri ini

, kami mengembangkan dua biji sederhana: kacang penggera bukan visual dan kacang panah kiri / panah kanan grafik. Kedua-duanya ditambah dengan visual

penyesuai

dan

maklumat kacang

kelas. Dalam kacang yang kita tutup bulan ini, kita tidak akan menyediakan penyesuai; sebaliknya, kami akan menumpukan perhatian pada penggunaan kacang dan komponen yang ada untuk menghasilkan kacang yang lebih besar dan lebih baik.

Prasyarat

Sebagai kesinambungan dari siri dua bahagian, saya akan menganggap terbiasa dengan isu-isu yang dibincangkan dalam ansuran sebelumnya, termasuk artikel dan sumber tambahan.

Kacang

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

AlarmBean Kacang bukan grafik yang memicu peristiwa selepas kelewatan yang ditentukan.
ArrowBean

Kacang anak panah kiri / panah kanan grafik.

ProgressBean

Kacang paparan kemajuan grafik.

NumberFieldBean

TextFieldBiji berangka grafik dengan butang gulung. Kacang ini menggunakan kacang ArrowBean.

FontChooserBean

Kacang pemilih fon grafik. Kacang ini menggunakan kacang NumberFieldBean.

FontSelectorBean

Biji pemilih fon grafik yang memaparkan fon semasa dan menyediakan butang OK / Batal. Kacang ini menggunakan kacang FontChooserBean.

FontDialogBean

Biji pemilih fon grafik yang muncul pemilih fon dalam dialog yang berasingan. Kacang ini menggunakan kacang FontSelectorBean.

Kami membincangkan kacang AlarmBeandan ArrowBeankacang secara terperinci bulan lalu; dalam episod ini, kita akan membincangkan baki kacang dengan pelbagai tahap terperinci.

Anda mungkin tertanya-tanya mengapa kami membina tiga biji fon. Tujuan utamanya ialah menghasilkan kacang pemilih fon yang memunculkan dialog fon ketika pengguna mengklik butang. Tugas ini secara semula jadi terbahagi kepada tiga biji yang akan kita hasilkan: Yang pertama adalah antara muka pengguna untuk pemilihan fon, yang kedua menambah kawalan dialog dan sampel fon, dan yang ketiga memperkenalkan butang untuk memunculkan dialog dan mengandungi dasar kod pengendalian dialog.

Tanpa kacang, kita perlu mengembangkan barang-barang ini sebagai komponen AWT khusus atau sebagai kelas monolitik tunggal; dengan menggunakan kacang, kita dapat mengembangkan ketiga-tiga bahagian itu sebagai kacang bebas yang boleh digunakan semula dengan sendirinya.

Skop kami

Seperti ansuran pertama siri ini, kami hanya mementingkan beanisme kelas ini dan bukan mur dan baut sebenar yang menjadikannya kutu. Hasilnya, kami akan membincangkan kacang dalam bentuk kerangka, dengan menyoroti warna-warna serpihan yang sangat relevan, dan meninggalkan butiran lain untuk anda baca dengan teliti pada masa lapang. Kita juga tidak akan membimbangkan diri kita dengan penyesuai, yang kita bahas secara terperinci dengan perbincangan kita mengenai dua biji pertama.

Untuk melihat kerja paksa di belakang kacang, periksa kod sumber lengkap.

Membina kacang ProgressBean

ProgressBean

adalah kacang paparan kemajuan sederhana. Ini adalah komponen AWT khusus yang memaparkan nilai peratusan dan representasi bar grafik dari nilai ini, seperti yang ditunjukkan dalam gambar di bawah. Ia memaparkan dua sifat: nilai bar semasa dan maksimum.

Nilai semasa didedahkan sebagai harta benda yang dapat diperhatikan . Sifat yang dapat diperhatikan adalah sifat yang perubahannya dapat diperhatikan. Pemerhati didaftarkan dengan kacang dengan cara yang sama seperti pendengar acara, dan mereka diberitahu setiap kali harta benda berubah. Sifat individu kacang mesti diperhatikan secara jelas oleh kacang; tidak mustahil untuk melihat perubahan pada harta tanah kacang apa pun.

Kacang ini dilaksanakan dengan dua kelas berikut:

  • ProgressBean - Kelas kacang utama

  • ProgressBeanBeanInfo - Kelas maklumat kacang

ProgressBean Kelas

The

ProgressBean kelas adalah kelas kacang utama, komponen AWT khas sederhana dan kacang Jawa.

kelas awam ProgressBean memperluas 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.

dilindungi Integer oValue = bilangan bulat baru (nilai); dilindungi void fireValueChange () {listeners.firePropertyChange ("value", oValue, oValue = new Integer (value)); }

Kita panggil kaedah ini untuk memberitahu pendengar perubahan dalam kita nilai harta; kami menggunakan firePropertyChange()kaedah senarai kami untuk menyebarkan pemberitahuan ini. Parameter pertama adalah nama harta tanah, yang harus sepadan dengan nama harta yang terdedah; parameter kedua adalah nilai lama harta tanah; dan harta ketiga adalah nilai baru. The PropertyChangeSupportpulangan kelas tanpa melakukan apa-apa jika nilai-nilai lama dan baru adalah sama.

Kemajuan KelasBeanBeanInfo

The

ProgressBeanBeanInfokelas hanya menerangkan ProgressBeankacang, mengaburkan segala maklumat yang diwarisi yang ingin kami kaburkan.

Membina 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 memaparkan lajurint sifat , minimum , maksimum , dan langkah , yang masing-masing adalah jumlah lajur yang ditunjukkan dalam , nilai minimum dan maksimum yang harus dimiliki oleh bidang ini, dan jumlah butang anak panah harus mengubah nilai. Sifat-sifat ini tidak dapat dilihat.TextField

Perhatikan bahawa kami menggunakan penyegerakan untuk memastikan keselamatan benang di mana sesuai.

tindakan void yang disegerakkan awamPerformed (ActionEvent e) {int value = getValue (); jika (e.getSource () == bawah) {if (nilai> minimum) {nilai = (nilai - langkah> nilai)? minimum: pengapit (nilai - langkah); setValue (nilai); }} ...