В.В. Кулямин - Технологии программирования. Компонентный подход (1133554), страница 51
Текст из файла (страница 51)
Каждое свойство имеетодин или оба метода доступа get и set,которые определяют действия, выполняемыепри чтении и модификации этого свойства. Обаметода доступа описываются внутридекларации свойства. Метод set используетспециальный идентификатор value для ссылкина устанавливаемое значение свойства.Обращение к свойству — чтение (возможно,только если у него есть метод get) илиизменение значения свойства (возможно, толькоесли у него есть метод set) — происходит также, как к полю.При перегрузке свойства в наследникахперегружаются методы доступа к нему.Пример объявления свойств и их использованияприведен ниже.using System;public class MyArrayList{private int[] items = new int[10];private int size = 0;public class MyArrayList{private int[] items = new int[10];private int size = 0;public int getSize(){return size;}public int Size{get { return size; }}public int getCapacity(){return items.Length;}public int Capacity{get { return items.Length; }set{int[] newItems = new int[value];Array.Copy(items, newItems, size);items = newItems;}}public void setCapacity(int value){int[] newItems = new int[value];System.arraycopy(items, 0, newItems, 0, size);items = newItems;}public static void main(String[] args){public static void Main(){178MyArrayList l = new MyArrayList();System.out.println(l.getSize());System.out.println(l.getCapacity());l.setCapacity(50);System.out.println(l.getSize());System.out.println(l.getCapacity());}}JavaBeans определяет индексированноесвойство (indexed property) класса A, имеющееимя name и тип T, как один или пару методов TgetName(int) и void setName(int, T).Свойства могут быть индексированы толькоодним целым числом.
В дальнейшемпредполагалось ослабить это ограничение иразрешить индексацию несколькимипараметрами, которые могли бы иметь разныетипы. Однако с 1997 года, когда появиласьпоследняя версия спецификаций JavaBeans [9],этого пока сделано не было.MyArrayList l = new MyArrayList();Console.WriteLine( l.Size );Console.WriteLine( l.Capacity );l.Capacity = 50;Console.WriteLine( l.Size );Console.WriteLine( l.Capacity );}}Индексированное свойство или индексер(indexer) — это свойство, зависящее от наборапараметров.В C# может быть определен только одининдексер для типа и данного набора типовпараметров. Т.е.
нет возможности определятьсвойства с разными именами, но одинаковыминаборами индексов.Обращение к индексеру объекта (или класса,т.е. статическому) производится так, как будтоэтот объект (класс) был бы массивом,индексированным набором индексовсоответствующих типов.При перегрузке индексера в наследникахперегружаются методы доступа к нему.Индексеры должны быть нестатическими.Обращение к индексеру класса-предка виндексере наследника организуется с помощьюконструкции base[…].Пример декларации и использования индексераприведен ниже.using System;public class MyArrayList{int[] items = new int[10];int size = 0;public int getItem(int i){if (i < 0 || i >= 10) throw newIllegalArgumentException();else return items[i];}public void setItem(int i, int value){if (i < 0 || i >= 10) throw newIllegalArgumentException();else items[i] = value;}public static void main(String[] args){MyArrayList l = new MyArrayList();l.setItem(0, 23);l.setItem(1, 75);l.setItem(1, l.getItem(1)-1);l.setItem(0,public class MyArrayList{int[] items = new int[10];int size = 0;public int this[int i]{get{if (i < 0 || i >= 10) throw newIndexOutOfRangeException();else return items[i];}set{if (i < 0 || i >= 10) throw newIndexOutOfRangeException();else items[i] = value;}}public static void Main(){MyArrayList l = new MyArrayList();l[0] = 23;l[1] = 75;l[0] += (--l[1]);Console.WriteLine(l[0]);179l.getItem(0) + l.getItem(1));System.out.println (l.getItem(0));System.out.println (l.getItem(1));}}События (events) в модели JavaBeans служатдля оповещения набора объектовнаблюдателей (listeners) о некоторыхизменениях в состоянии объекта-источника(source).При этом класс EventType объектов,представляющих события определенного вида,должен наследовать java.util.EventObject.Все объекты-наблюдатели должныреализовывать один интерфейс EventListener,в котором должен быть метод обработкисобытия (обычно называемый так же, как исобытие) с параметром типа EventType.Интерфейс EventListener должен наследоватьинтерфейсу java.util.EventListener.Класс источника событий должен иметь методыдля регистрации наблюдателей и их удаления изреестра.
Эти методы должны иметь сигнатурыpublic void addEventListener(EventListener)public void removeEventListener(EventListener).Можно заметить, что такой способ реализацииобработки событий воплощает образецпроектирования «Подписчик».В приведенном ниже примере все publicклассы и интерфейсы должны быть описаны вразных файлах.public class MouseEventArgs { ... }}}Console.WriteLine(l[1]);Событие (event) представляет собой свойствоспециального вида, имеющее делегатный тип.
Усобытия, в отличие от обычного свойства,методы доступа называются add и remove ипредназначены они для добавления илиудаления обработчиков данного события,являющихся делегатами (это аналоги различныхреализаций метода обработки события винтерфейсе наблюдателя в JavaBeans) припомощи операторов += и -=.Событие может быть реализовано как поледелегатного типа, помеченное модификаторомevent. В этом случае декларироватьсоответствующие методы add и removeнеобязательно — они автоматическиреализуются при применении операторов += и-= в к этому полю как к делегату.Если же программист хочет реализовать какоето специфическое хранение обработчиковсобытия, он должен определить методы add иremove.В приведенном ниже примере одно из событийреализовано как событие-поле, а другое — припомощи настоящего поля и методов add иremove, дающих совместно тот же результат.При перегрузке события в наследникахперегружаются методы доступа к нему.public class MouseEventArgs { ...
}public class MouseEventObjectextends java.util.EventObject{MouseEventArgs args;}MouseEventObject(Object source, MouseEventArgs args){super(source);this.args = args;}public interface MouseEventListenerextends java.util.EventListener{void mouseUp(MouseEventObject e);void mouseDown(MouseEventObject e);}public delegate void MouseEventHandler(object source, MouseEventArgs e);import java.util.ArrayList;public class MouseEventSourcepublic class MouseEventSource180{private ArrayList<MouseEventListener>listeners = new ArrayList<MouseEventListener >();{private MouseEventHandler mouseDown;public eventMouseEventHandler MouseDown{add{lock(this){ mouseDown += value; }}remove{lock(this){ mouseDown -= value; }}}public synchronized voidaddMouseEventListener(MouseEventListener l){ listeners.add(l); }public synchronized voidremoveMouseEventListener(MouseEventListener l){ listeners.remove(l); }protected void notifyMouseUp(MouseEventArgs a){MouseEventObject e =new MouseEventObject(this, a);ArrayList<MouseEventListener> l;synchronized(this){l =(ArrayList<MouseEventListener>)listeners.clone();for(MouseEventListener el : l)el.mouseUp(e);}}protected voidOnMouseUp(MouseEventArgs e){MouseUp(this, e);}protected void notifyMouseDown(MouseEventArgs a){MouseEventObject e =new MouseEventObject(this, a);}}ArrayList<MouseEventListener> l;synchronized(this){l =(ArrayList<MouseEventListener>)listeners.clone();for(MouseEventListener el : l)el.mouseDown(e);}public class HandlerConfigurator{MouseEventSource s =new MouseEventSource();MouseEventListener listener =new MouseEventListener(){public void mouseUp(MouseEventObject e) { ...
}public void mouseDown(MouseEventObject e) { ... }};public event MouseEventHandler MouseUp;}protected voidOnMouseDown(MouseEventArgs e){mouseDown(this, e);}public class HandlerConfigurator{MouseEventSource s =new MouseEventSource();public void UpHandler(object source, MouseEventArgs e){ ... }public void DownHandler(object source, MouseEventArgs e){ ... }181}public void configure(){s.addMouseEventListener(listener);}}public void Configure(){s.MouseUp += UpHandler;s.MouseDown += DownHandler;}Методы доступа к свойствам, индексерам илисобытиям в классах-наследниках могутперегружаться по отдельности, т.е., например,метод чтения свойства перегружается, а методзаписи — нет.В C# 2.0 введена возможность декларацииразличной доступности у таких методов.Например, метод чтения свойства можносделать общедоступным, а метод записи —доступным только для наследников.Для этого можно описать свойство так:public int Property{get { … }protected set { … }}В Java никакие операторы переопределитьнельзя.Вообще, в этом языке имеются толькооператоры, действующие на значенияхпримитивных типах, сравнение объектов наравенство и неравенство, а также оператор + длястрок (это объекты класса java.lang.String),обозначающий операцию конкатенации.Оператор + может применяться и к другимтипам аргументов, если один из них имеет типString.
При этом результатомсоответствующей операции являетсяконкатенация его и результата примененияметода toString() к другому операнду впорядке следования операндов.Некоторые операторы в C# можнопереопределить (перекрыть) для данногопользовательского типа. Переопределяемыйоператор всегда имеет модификатор static.Переопределяемые унарные операторы (ихединственный параметр должен иметь тот тип,в рамках которого они переопределяются, илиобъемлющий тип): +, -, !, ~ (в качестве типарезультата могут иметь любой тип), ++,-- (типих результата может быть только подтипомобъемлющего), true, false (тип результатаbool).Переопределяемые бинарные операторы (хотябы один из их параметров должен иметьобъемлющий тип, а возвращать они могутрезультат любого типа): +, -, *, /, %, &, |, ^, <<,>>, ==, !=, <, >, <=, >=.
Для операторов сдвига <<и >> ограничения более жесткие — первый ихпараметр должен иметь объемлющий тип, авторой быть типа int.Можно определять также операторыприведения к другому типу или приведения издругого типа, причем можно объявить такоеприведение неявным с помощью модификатораimplicit, чтобы компилятор сам вставлял еготам, где оно необходимо для соблюденияправил соответствия типов. Иначе надоиспользовать модификатор explicit и всегдаявно приводить один тип к другому.Некоторые операторы можно определять толькопарами — таковы true и false, == и !=, < и >,182<= и >=.Операторы true и false служат для неявногопреобразования объектов данного типа ксоответствующим логическим значениям.Если в типе T определяются операторы & и |,возвращающие значение этого же типа, а такжеоператоры true и false, то к объектам типаможно применять условные логическиеоператоры && и ||.