63470

Спецификация JavaBeans

Лекция

Информатика, кибернетика и программирование

Для того, чтобы класс Java можно было назвать компонентом JavaBeans, он должен удовлетворять перечисленным ниже требованиям: Способность к инициализации нового экземпляра. Компоненты JavaBeans нельзя создавать на основе интерфейсов и абстрактных классов.

Русский

2014-06-20

158 KB

0 чел.

I. Спецификация JavaBeans                                                                                                          Лекция 5.

Что такое компонент JavaBeans

Для того, чтобы класс Java можно было назвать компонентом JavaBeans, он должен удовлетворять перечисленным ниже требованиям:

- Способность к инициализации нового экземпляра. Компоненты JavaBeans  нельзя создавать на основе интерфейсов и абстрактных классов.

- Наличие принимаемого по умолчанию конструктора. Если класс называется MyBean, необходимо, чтобы он имел конструктор без параметров MyBean ( ).

- Возможность сериализации. В компоненте должен быть реализован интерфейс Serializable или Externalizable, который позволяет копировать содержимое компонента в поток в виде последовательности данных.

Наличие интерфейса Externalizable позволяет полностью контролировать способ записи класса в поток. Однако чаще всего этого не требуется, достаточно обеспечить лишь запись и чтение байтов данных.

- Совместимость со стандартами проектирования компонентов JavaBeans. Специалистами фирмы Sun разработано несколько простых правил, которым необходимо следовать для удовлетворения соглашения об именах и методах проектирования.

!!! Предлагаемые стандарты проектирования можно полностью игнорировать, если указать в файле BeanInfo выбранный Вами интерфейс.

- Использование моделей делегирования событий. При использовании событий необходимо обрабатывать или генерировать их согласно новой модели, предложенной в JDK 1.1.

Стандарты проектирования компонентов JavaBeans можно подытожить в виде набора из пяти правил:

1. Для простых свойств в программе должны быть созданы методы типа getProperty ( ) и setProperty ( ).

Причем первый из них должен возвращать данные того же типа, что и данные, который передаются второму методу. Если свойство используется только для чтения, следует опустить реализацию метода setProperty ( ), а если только для записи, следует опустить реализацию метода getProperty ( ).

2. Если свойство имеет логический тип данных (boolean), то метод getProperty ( ) можно заменить эквивалентным методом isProperty ( ). Таким образом, вместо кода

                          boolean getDouble ( )

                          setDouble (boolean theValue)

можно использовать следующий код:

                          boolean isDouble ( )

                          setDouble (boolean theValue)

Замечание. Простые свойства должны начинаться с field:

                          int fieldProperty

3. Допускается добавление индексированного свойства, т.е. свойства, представленного в виде массива. Подобная возможность реализуется либо использование обычного соглашения об именах с префиксами get и set (так же как и передача ссылки на весь массив), либо созданием специальных индексированных версий методов getProperty ( ) и setProperty ( ). Например, для свойства Rainbow, представленного массивом значений цветов Color, можно использовать код

 

                          Color getRainbow (int theColorNumber)

                          setRainbow (int theColorNumber, Color theColor)

или следующий традиционный подход:

 

                          Color [ ] getRainbow ( )

                          setRainbow (Color [ ] theColors)

Замечание. SmurtGuide использует оба способа. Следовательно, для удобства пользователя необходимо также применять эти два подхода.

4. При создании события нужно использовать описанный ниже стандартный подход, где интерфейс EventTypeListener, является наследником интерфейса java.util. EventListener.

                      

                            public void addEventTypeListener (EventTypeListener the Event)

                            public void removeEventTypeListener (EventTypeListener the Event)

Если для событий одноадресной (unicast) доставки сообщений необходимо применять обработку  исключительных ситуаций, то в объявлении метода следует использовать директиву throws TooManyListenerException.

5. Все открытые методы доступны для использования визуальными инструментами разработки и другими пользователями.  

Механизм событий

Согласно спецификациям JavaBeans, у каждого события есть источник и, быть может, один или несколько подписчиков (получателей).

Источник обязан:

- выбрать имя метода, вызываемого в компонентах-подписчиках при распространении события. Этот метод должен содержаться в интерфейсе, который является расширением интерфейса EventListener (данное расширение мы будем называть интерфейсом  события);

- реализовать метод регистрации подписчиков события и метод аннулирования регистрации;

- при распространении события вызвать метод, описанный в интерфейсе события, во всех компонентах-подписчиках.

В свою очередь, подписчик должен предпринять следующие действия:

- выполнить реализацию интерфейса события, то есть по сути реализовать метод обработки события (напомним, что имя этого метода выбрал источник);

- зарегистрироваться в качестве подписчика события.

Рассмотрим перечисленные шаги более подробно. Действия, выполняемые источником события

Источник события по своему выборку назначает имя методу, вызываемого компонентах-подписчиках при распространении события. Чтобы сделать возможной автоматическую интроспекцию компонентов на предмет распространяемых ими событий ( то есть для поддержки рефлексии), данный метод описывается в расширении пустого интерфейса java.util. EventListener, играющего роль этикетки.

  

interface KeyPressedListener extends java.util. EventListener {

        void KeyPressed (KeyPressedEvent kpe);

        / / Метод, вызываемый в подписчиках

       / /  при распространении события

}

По соглашению, опять-таки направленному на поддержку рефлексии, имя интерфейса-расширения должно оканчиваться цепочкой символов Listener”. Если источник желает распространять несколько различных событий, допускается описание в одном интерфейсе соответствующего числа методов их обработки.

Метод обработки события должен иметь один аргумент, которым является так называемый событийный объект – преемник класса java.util. EventObject. Посредством этого объекта подписчику передается информация об источнике и другие характеристики события.

Определение класса EventObject приведено ниже.

public class EventObject extends Object implements Serializable {

protected transient Object sourse;

/ / Поле событийного объекта, хранящее информацию об источнике.

/ / Слово transient означает, что поле является временным и

/ / при сохранении объекта в долговременную память не записывается

public EventObject (Object source);

public Object getSource ( );

public String toString ( );

}

Далее приведено возможное описание класса KeyPressedEvent (окончание Event– еще одно требование рефлексии).

public class KeyPressedEvent extends java.util. EventObject    {

     

        protected transient int KeyCode;

        KeyPressedEvent (java.awt.Component source, int Key) {

                    super (source);

                    KeyCode = Key;

        }

public int getKeyPressed ( )  {

         return KeyCode;

        }

}

Реализация методов регистрации подписчиков, аннулирования регистрации, а также собственно распространения события может быть выполнена способом, приведенном ниже. Отметим, что при распространении события вызов методов подписчиков производится синхронным образом, в рамках потока источника события.

public abstract class KeyPressedEventSource   {

         private Vector listeners = new Vector ( );

         / / Массив для хранения набора подписчиков

        public synchronized void addKeyPressedListner (KeyPressedListener kpl) {

                  / / Зарегистрировать подписчика

                  listeners.addElement (kp1);

        }

        public synchronized void removeKeyPressedListener (KeyPressedListener kpl) {

                  / / Аннулировать регистрацию

                  listeners.removeElement (kp1);

        }

        protected fireKeyPressed (int Key) {

                  / / Распространение события (оповещение подписчиков)

                 Vector l;

                 KeyPressedEvent kpe=new KeyPressedEvent (this, Key);

                 / / Создадим локальную копию набора подписчиков

                 / / на момент возникновения события.

                 / / В процессе распространения события набор подписчиков

                 / / (но не локальная копия!) может изменяться

                 synchronized (this)

                 {    l = (Vector) listeners.clone ( );}

                 / / Оповестим подписчиков о наступлении события

                for (int i = 0; i < l.size ( ); i++)  {

                       (  (KeyPressedListener)

                       l.elementAt (i ) ). KeyPressed (kpe);

                }      

                 }

}

Обратим внимание на два аспекта программа текста, приведенного выше. Во-первых, в источнике необходимо обеспечить безопасность работы в многопотоковой среде. Методы add / remove выполняются в рамках потоков подписчиков, поэтому они нуждаются в синхронизации. В методе fire также следует учитывать возможность регистрационных действий параллельно с распространением события. Отсюда три вхождения ключевого слова synchronized.

Во-вторых, регистрационные методы должны поддерживать рефлексию и определяться по следующим шаблонам:

public void add< имя интерфейса события>

   (< имя интерфейса события>подписчик);

public void remove< имя интерфейса события>

   (< имя интерфейса события>подписчик);

Определение метода fire – внутреннее дело источника события.

Действия, выполняемые подписчиком события.

 

Реализация интерфейса события – основное действие, выполняемое подписчиком. Его содержательная сторона зависит от специфики подписчика. Чисто технические моменты отражены ниже:

public class MyListener implements KeyPressedListener  {

         public void KeyPressed (KeyPressedEvent kpe)  {

         .  .  .

         }

}

Регистрация подписки производятся обращением к соответствующему add-методу источника события.

     

Если проводить аналогию с обычной подпиской на газеты и журналы, то базовый механизм, описанный в спецификациях JavaBeans, соответствует оформлению подписки в редакции каждого издания (а не в отделении связи). В спецификациях упоминается также о возможности реализации адаптеров (adapter) – посредников, берущих на себя централизованное оформление подписки и реализацию определенной дисциплины распространения событий.

Адаптер реализует все методы интерфейса, оставляя их пустыми (они ничего не делают). Вам остается унаследовать от подходящего адаптера и переопределить те методы, что вас интересуют. Например:

class MyWindowListener extends WindowAdapter   {

         public void windowClosing (WindowEvent e)  {

                    System.exit (0);

         }

}

Однако ничто не совершенно, и адаптеры в том числе – при их использовании легко попасть в ловушку.

Например:

class MyWindowListener extends WindowAdapter   {

         public void WindowClosing (WindowEvent e)  {

                    System.exit (0);

         }

}

Преимущество интерфейсов. Хотя их неудобно использовать, они гарантируют, то что будут реализованы те методы, что нужно.

При установлении взаимодействия между источниками и подписчиками событий значительная часть работы может быть выполнена инструментальной средой. Эта среда может сгенерировать код, содержащий

обращение к add-методам, обеспечить согласованность названий методов обработки событий, сгенерировав при необходимости вспомогательные классы, и т.п.

Свойства компонентов JavaBeans

К описанной выше спецификации организации доступа к свойствам компонентов, реализуемой в использовании специальных методов выборки и установки следует добавить связи между свойствами разных компонентов.

Между свойствами разных компонентов могут существовать связи двоякого рода. Во-первых, при изменении одного свойства может потребоваться модификация других свойств или иных характеристик. Такие свойства называются связанными (bound). Во-вторых, некоторые изменения могут трактоваться как некорректные и запрещаться. Соответствующие свойства называются ограниченными (constrained). Тем самым спецификации JavaBeans предоставляют средства контроля целостности объектной среды.

Свойства компонентов могут подвергаться настройке. Обычно настройка производится в инструментальном окружении при сборке приложений, однако, вообще говоря, она может осуществляться и во время выполнения.

Спецификации JavaBeans предусматривают наличие связных свойств, после изменения которых  возбуждается событие propertyChange. Другие компоненты могут подписаться на это событие и, следовательно, получать информацию о производимых изменениях, анализируя объект-параметр PropertyChangeEvent, фрагмент описания которого приведен ниже:

            

public class PropertyChangeEvent extends EventObject {

         public class PropertyChangeEvent   (Object    source,   String      propertyName,      Object

         oldValue, Object newValue);

         / / Конструктор. Создает событийный объект из источника.

         / / события, имени изменяемого свойства,

         / / старого и нового значений

        public String getPropertyName ( );

        / / Возвращает имя изменяемого свойства

        public Object getNewValue ( );

        / / Возвращает новое значение свойства

 

        public Object getOldValue ( );

        / / Возвращает прежнее значение свойства

.  .  .

}

Метод propertyChange, вызываемый для обработки изменения значения свойства, описан в интерфейсе PropertyChangeListener. Источник события, в соответствии с общими правилами, должен реализовать методы addPropertyChangeListener и removePropertyChangeListener, обеспечивая регистрацию подписчиков.

public interface PropertyChangeListener extends EventListener  {

         public abstract void

         propertyChange (PropertyChangeEvent pce);

         / / Метод, вызываемый после изменения

         / / связанного свойства

}

Вспомогательный класс PropertyChangeSupport, входящий в пакет java.beans, реализует рутинные действия, характерные для обслуживания связанных свойств. Естественно, разработчики компонентов могут воспользоваться этим классом.

public class PropertyChangeSupport extends Object implements Serializable {

 /  / Вспомогательный класс для обслуживания

/ / связанных свойств

public PropertyChangeSupport extends (Object sourceBean);

/ / Конструктор

public synchronized void addPropertyChangeListener (PropertyChangeListener

pcl);

/ / Регистрация подписчиков

public synchronized void

removePropertyChangeListener (PropertyChangeListener pcl);

/ / Аннулирование регистрации

public void firePropertyChange (String propertyName, Object oldValue,  

Object newValue);

/ / Конструирование событийного объекта и

/ / распространение события. Если новое и старое значения

/ / совпадают, никаких действий не предпринимается.

}

Помимо связанных, спецификации JavaBeans описывают ограниченные свойства, перед изменением значений которых распространяется событие vetoableChange c параметром PropertyChangeEvent. Подписчики этого события могут отклонить планируемое событие, возбудив исключительную ситуацию PropertyVetoException. Метод set должен отреагировать на подобное вето, вернув прежнее значение, «извинившись» перед уже оповещенными подписчиками (то есть, вызвав их методы  vetoableChange c обратной парой новое/старое значение) и передав исключительную ситуацию инициатору изменения. Соответственно, заголовок set-метода для ограниченных свойств приобретает следующий вид:

public void set <имя_свойства> (<тип_свойства> p) throws PropertyVetoException;

Синтаксически связанные и ограниченные свойства аналогичны, но реализация последних требует гораздо

большей аккуратности и  от источников (set-методов), и от подписчиков события vetoableChange. Источнику рекомендуется воспользоваться вспомогательным классом java.beans.VetoableChangeSupport,

аккуратно выполняющим все необходимые действия. Подписчикам будет проще, если сделать свойство и ограниченным, и связанным. В таком случае до изменения (при обработке события vetoableChange) подписчики заботятся только о голосовании «за» и «против», а после изменения (при обработке события propertyChange) они выясняют, каким же стало новое значение.

Основные события библиотеки Swing

Событие, интерфейс слушателя и методы

                добавления, удаления  

Компоненты, поддерживающие это событие

Методы интерфейса

Действие (например, нажатие кнопки)

JButton, JList, JTextField, JMenuItem  и 

ActionEvent

наследование от них, включая

ActionListener

JCheckBoxMenuItem, JMenu и JpopupMenu.

addActionListener ( )

removeActionListener ( )

actionPerformed (ActionEvent)

Регулировка некоторого значения

JScrollbar и все, что вы создаете, реализуя  

AdjustmentEvent

Adjustable interface.

AdjustmentListener

addAdjustmentListener ( )

adjustmentValueChanged (AdjustmentEvent)

removeAdjustmentListener ( )

*Component и наследованные от него, включая

Общие для всех компонентов события

JButton, JCanvas, JCheckBox, JComboBox,

Container, JPanel, JApplet, JscrollPane,

ComponentEvent

Window, JDialog, JFileDialog, JFrame, JLabel,

ComponentListener

JList, JScrollbar, JTextArea и JtextField.

addComponentListener ( )

removeComponentListener ( )

componentHidden (ComponentEvent)

componentShown (ComponentEvent)

componentMoved (ComponentEvent)

componentResized (ComponentEvent)

Общие для всех контейнеров события

Container и наследование от него, включая

JPanel, Japplet, JScrollPane, Window,

ContainerEvent

JDialog, JfileDialog и JFrame.

ContainerListener

addContainerListener ( )

componentAdded (ContainerEvent)

removeContainerListener ( )

componentRemoved (ContainerEvent)

Получение или потеря компонентом фокуса

Component  и унаследованные*. 

FocusEvent

FocusListener

focusGained (FocusEvent)

addFocusListener ( )

focusLost (FocusEvent)

removeFocusListener ( )

Нажатие клавиши на клавиатуре

Component  и унаследованные*. 

KeyEvent

KeyListener

keyPressed (KeyEvent)

addKeyListener ( )

keyReleased (KeyEvent)

removeKeyListener ( )

keyTyped (KeyEvent)

Перемещение мыши и нажатие на ее кнопки

Component  и унаследованные*. 

MouseEvent

mouseClicked (MouseEvent)

MouseListener

mouseEntered (MouseEvent)

addMouseListener ( )

mouseExited (MouseEvent)

removeMouseListener ( )

mousePressed (MouseEvent)

mouseReleased (MouseEvent)

Перемещение мыши

Component  и унаследованные*.

MouseEvent

 

MouseMotionListener

mouseDragged (MouseEvent)

addMouseMotionListener ( )

mouseMoved (MouseEvent)

removeMouseMotionListener ( )

Window и унаследованные от него, включая

Оконные события (напр., закрытие окна)

JDialog, JFileDialog и JFrame.

WindowEvent

windowOpened (WindowEvent)

WindowListener

windowClosing (WindowEvent)

addWindowListener ( )

windowClosed (WindowEvent)

removeWindowListener ( )

windowActivated (WindowEvent)

windowDeactivated (WindowEvent)

windowIconfied (WindowEvent)

windowDeiconfied (WindowEvent)

Выбор некоторого элемента

ItemEvent

JcheckBox, JcheckBoxMenuItem, JComboBox,

ItemListener

JList и все, что реализует ItemSelectable 

addItemListener ( )

interface.

removeItemListener ( )

Текстовые события (напр., удаление текста)

Все, что унаследовано от JTextComponent,

TextEvent

включая, JtextArea и JtextField.

TextListener

addTextListener ( )

TextValueChanged (TextEvent)

removeTextListener ( )

II. Интроспекция.

В среде JavaBeans существуют способы динамического ( то есть не по исходным текстам ) выяснения характеристик компонентов. К таким характеристикам относятся:

- методы, доступные для вызова другими компонентами и инструментальными окружением;

- свойства, которые можно опрашивать и/или изменять;

- события, порождаемые данным компонентом.

Интроспекция используется, прежде всего на этапе разработки, в рамках инструментального окружения, позволяя увидеть афишируемые характеристики и с их помощью настроить компонент и связать его с другими элементами приложения.

Принципиальная возможность интроспекции была изначально заложена в Java-технологии. Файлы классов содержат достаточно информации для выяснения всех необходимых характеристик объектов. Воспользоваться этой информацией можно с помощью класса Class  и пакета java.lang.reflect.

Class java.lang.Class

getConstructors ( )

getDeclaredFields ( )

getDeclaredMethods ( )

getFields ( )

getMethods ( )

getModifiers ( )

isInterfase ( )

isPrimitive ( )

Package java.lang.reflect

Class java.lang.reflect.Constructor

equals (Object)

getName ( )

newInstance (Object [ ])


Class java.lang.reflect.Field

equals (Object)

get (Object)

getBoolean (Object), getByte (Object), . . .

set (Object, Object)

setBoolean (Object, boolean), setByte (Object, byte), . . .

Class java.lang.reflect.Method

equals (Object)

getExceptionTypes ( )

getModifiers ( )

getParameterTypes ( )

getReturnType ( )

invoke (Object, Object [ ])

Пример:

static void modifyWidth (Rectangle r, Integer widthPar)  {

        Field widthField

        Class с = r.getClass ( );

        try {

                   widthField = c. getField (”width”);

                   widthField.set (r, widthParam);

        } catch (NoSuchFieldException e) {

                   print (e);

        } catch (IllegalAccessException e) {

                   print (e);

        }

}

Задания к практическим занятиям:

1. Создать простой класс, удовлетворяющий спецификации JavaBeans: 2-3 поля полей, методы, события.

2. Создать класс, который будет выстреливать ваше собственное событие. Для этого создайте собственное событие и интерфейс его слушателя (можно через SmartGuide странички BeanInfo класса, выстреливающего событие).

а) через переменную класса-события проследите, что оно происходит (введите строковое поле в классе-событии и соедините его с окном ввода).

б) создайте класс-слушатель вашего события (реализуйте интерфейс его слушателя). Затем подпишитесь у источника события. Проследите, как это работает.

3. Создайте класс с constrained свойством. Обновляйте его через окно-ввода. Создайте класс-наследник  от окна ввода, в котором будете отслеживать изменения ограниченного поля. Определите границы изменения этого поля. Для этого реализуйте в нем интерфейс java.beans.VetoableChangeListener и подпишитесь на ограничение события.


 

А также другие работы, которые могут Вас заинтересовать

6292. Средства, влияющие на периферическую нервную систему 99.5 KB
  Средства, влияющие на периферическую нервную систему. В периферической нервной системе различают афферентную и эфферентную ее части. Нервные волокна, проводящие возбуждение от органов и тканей к ЦНС, называются афферентными, а от ЦНС к органам и тка...
6293. Холиномиметики, ганглиоблокаторы и холиноблокаторы 98 KB
  Холиномиметики В холинергических синапсах (парасимпатические нервы, преганглионарные симпатические волокна, ганглии, все соматические) передача возбуждения осуществляется медиатором ацетилхолином. Ацетилхолин образуется из холина и ацетилхоэнзима А ...
6294. Конструкционные материалы. Легированные стали 76 KB
  Конструкционные материалы. Легированные стали. Конструкционные стали. Легированные стали Влияние элементов на полиморфизм железа Влияние легирующих элементов на превращения в стали Влияние легирующих элементов на превращение ...
6295. Кредитная система, ее структура 67.5 KB
  Кредитная система, ее структура. Понятие кредитной системы и ее структура в Республике Беларусь. Банковская система, ее виды. Перспективы развития национальной банковской системы. На сегодняшний день в Беларуси насчитывается 32 ком...
6296. Конструкционные стали. Классификафия конструкционных сталей 62 KB
  Конструкционные стали. Классификафия конструкционных сталей. Классификация конструкционных сталей Углеродистые стали. Цементуемые и улучшаемые стали Цементуемые стали. Улучшаемые стали. Высокопрочные, пружинные, шарико...
6297. Фармакопейный анализ спиртов и простых эфиров 138 KB
  Фармакопейный анализ спиртов и простых эфиров Спирты R—ОН Спирты можно рассматривать как углеводороды, в которых один или несколько атомов водорода замещены –ОН группами. В зависимости от числа гидроксильных г...
6298. Логические элементы на биполярных структурах 100.5 KB
  Логические элементы на биполярных структурах. Транзисторно-транзисторная логика (ТТЛ) удачно совмещает хорошее быстродействие, помехоустойчивость, нагрузочную способность с умеренным потреблением энергии и невысокой стоимостью...
6299. Коррозионно-стойкие стали и сплавы. Жаростойкие стали и сплавы. Жаропрочные стали и сплавы 85 KB
  Коррозионно-стойкие стали и сплавы. Жаростойкие стали и сплавы. Жаропрочные стали и сплавы Коррозия электрохимическая и химическая. Классификация коррозионно-стойких сталей и сплавов Хромистые стали. Жаростойкость, жаростойки...
6300. Элементы логики с инжэкционным питанием 93 KB
  Элементы логики с инжэкционным питанием. Интегрально-инжекционная логика (И2Л), которую вернее было бы назвать логикой с инжекционным питанием, не может быть реализована на дискретных компонентах. Вариант структуры логики ИгЛ, изготовленной, н...