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 |
|
|
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 AlarmBean
dan ArrowBean
kacang 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 utamaProgressBeanBeanInfo
- 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 PropertyChangeSupport
pulangan kelas tanpa melakukan apa-apa jika nilai-nilai lama dan baru adalah sama.
Kemajuan KelasBeanBeanInfo
The
ProgressBeanBeanInfo
kelas hanya menerangkan
ProgressBean
kacang, 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 classNumberFieldBeanBeanInfo
-- 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); }} ...