МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Практическая работа по теме 7. Архитектура и возможности семейства языков высокого уровня Описание свойств класса, как открытых или закрытых переменных. Использование конструкторов класса. Ограничение доступа к свойствам. Разделяемые переменные в классах. Тестирование классов. Синхронизация элементов управления формы. Классы работы с векторами и простыми дробями. Практическая работа по теме 7. Архитектура и возможности семейства языков высокого уровня .............................................................................................................................................1 Задание 1. Описание свойств класса, как открытых переменных ........................................1 Задание 2. Описание свойств класса, как закрытых переменных ........................................7 Задание 3. Использование конструкторов класса ................................................................10 Задание 4. Ограничение доступа к свойствам класса ..........................................................11 Задание 5. Разделяемые переменные в классах ....................................................................14 Задание 6. Синхронизация элементов управления...............................................................16 Задание 7. Создание класса Vector (свойства класса) ..........................................................18 Задание 8. Работа с простыми дробями.................................................................................19 Задание 9. Печатающаяся строка ...........................................................................................20 Задание 1. Описание свойств класса, как открытых переменных Задача Обеспечить хранение данных класса (свойств класса) в открытых переменных, то есть переменных, доступных объектам текущего класса или объектам других классов. Решение При описании свойств класса необходимо использовать ключевое слово (модификатор) Public. Обсуждение Класс является базовым понятием в объектно-ориентированном программировании. Класс, представляющий собой некоторый набор свойств (количественных или качественных описательных характеристик объекта), методов (процедур и/или функций) и событий, происходящих или не происходящих при выполнении методов класса, может быть описан как в отдельном библиотечном файле с последующим подключением к проекту, так и непосредственно в одном из модулей текущего проекта. В любом случае, описание класса в VB.NET следует выполнять в отдельном модуле, который создается через меню Project– Class МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Module. Имя класса лучше указывать сразу – при открытии модуля класса. Описание нового класса выполняется внутри следующей конструкции: Public Class ИмяКласса Описание класса: Описание свойств класса Описание методов класса Описание событий класса End Class Требуемое поведение объектов класса обеспечивается при помощи методов, свойств и событий, описанных в модуле класса. Этот процесс называется инкапсуляцией. Инкапсуляция – один из базовых принципов объектно-ориентированного программирования, наряду с полиморфизмом и наследованием. Все, что определяет класс, как единую структуру, должно размещаться в модуле класса под единым именем – именем класса. Свойства класса представляют собой переменные, инкапсулированные в структуру класса. Свойства описываются как переменные разных типов и разной области видимости (scope). Свойства класса могут быть описаны одним из способов: или как переменные класса с областью видимости Public, или как переменные класса с областью видимости Private. В любом случае эти переменные будут хранить значения свойств экземпляров класса. Public|Private ИмяСвойства As TypeObject Имена свойств, также как и имена переменных, должны подчиняться принятым ограничениям на использование допустимых символов. Имя свойства должно быть коротким, но достаточно значащим, позволяющим любому другому программисту интуитивно понять назначение свойства. Не забывайте, что одним из основных достоинств объектноориентированного программирования является повторное использование кода описания классов. Если переменные описываются с ключевым словом Public, то они доступны не только в рамках описания класса, но и извне, то есть экземпляры других классов, их методы, могут непосредственно обращаться к свойствам класса, описанным с областью видимости Public и изменять (вводить новые, удалять старые, редактировать) значения этих свойств. Попробуем создать класс, свойства которого будут объявлены с модификатором (ключевым словом) Public (публичный, общедоступный). В проекте создадим объекты такого класса и убедимся в том, что таким образом описанные свойства практически не защищены от действий других объектов по их изменению. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Единственной защитой, которая сработает автоматически, является проверка на соответствие типа назначаемого свойству значения, или программист должен при использовании таких объектов сам программировать степень доступа к свойствам объекта. Создайте новый Windows-проект, в модуле класса проекта опишите структуру класса Persona, инкапсулирующего два свойства – FullName и PersonaId для хранения фамилии сотрудника (персоны) и его персонального, например, табельного номера соответственно. Public Class Persona Public FullName As String Public PersonaId As Integer End Class Даже такого скромного описания класса уже вполне достаточно, чтобы иметь возможность создавать экземпляры класса Persona и обращаться к свойствам этих экземпляров. Dim Persona1 As New Persona Можно присваивать новые значения свойствам объекта: Persona1.FullName=”строка” Persona1.PersonaId=число или, наоборот: “строка”=Persona1.FullName Число=Persona1.PersonaId На самом деле, даже пустое содержание класса, но обязательно поименованного (имеющего имя), уже является классом. Public Class Class1 End Class1 Экземпляры такого класса тоже могут быть созданы. Пока мы не изучим механизм наследования классов, с объектами таких классов мы работать не сможем, так как нам кажется, что класс не имеет ни свойств, ни методов. Но следующая строчка кода не будет ошибкой Dim cl1 as New Class1 В Windows-форме спроектируем интерфейс для тестирования экземпляров созданного класса Persona. Примерный вид интерфейса представлен на рис. 7.1. Форма имеет командную кнопку «Свойства класса» для ввода информации об очередном клиенте, а также командную кнопку «Тест» и текстовое поле для вывода информации о сотруднике. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Рис. 7.1. Тестирование класса Persona Создание экземпляра класса опишем в обработчике события – нажатия кнопки «Свойства класса», а вывод информации в текстовое поле – в обработчике события нажатия кнопки «Тест». Dim Р As New Persona ’Создание экземпляра (объекта) класса Persona. P – это имя создаваемого объекта; New – конструктор любого класса, специальный метод, позволяющий создавать объекты класса. Вы удивитесь, что никаких методов в классе Persona мы еще не создавали, но любой класс автоматически имеет такой метод– конструктор. Этот конструктор не требует входных параметров, то есть он позволяет просто объявить объект обозначенного класса, не инициируя его свойств, методов или событий. В дальнейшем мы будем создавать собственные конструкторы наших классов: с параметрами или без них. Следует обратить внимание еще на одно обстоятельство: мы объявили объект P с областью видимости Dim, но в описании кода на уровне формы, другими словами, мы объявили объект с уровнем видимости – текущая форма проекта. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ’ Используем обработчик события щелчка по командной кнопке p.FullName = InputBox("Введите имя сотрудника") ‘Для организации диалога с пользователем используем стандартное ‘диалоговое окно InputBox, реализованное в виде функции, ‘возвращающей строковое значение p.PersonaId = CInt(InputBox("Укажите его код")) End Sub МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE В приведенном коде обработчика события «щелчок по командной кнопке Button1» мы начали работу с созданным объектом: присвоили свойству FullName значение, введенное пользователем в строку стандартного диалогового окна InputBox. Аналогичным образом происходит присвоение значения свойству объекта PersonaId, но так как стандартная функция InputBox возвращает значение типа String, а значение свойства PersonaId объявлено с типом Integer, требуется явное преобразование типов. Преобразование типов значений удобно выполнять с помощью стандартных функций, в нашем случае – CInt(). Обрабатывая нажатие другой командной, кнопки мы покажем в текстовом окне (присвоим свойству Text объекта TextBox1) информацию, созданную конкатенацией двух строк: p.FullName и p.PersonaId. Обратите внимание на еще один способ согласования типов переменных: у свойства объекта p.Personald, которое является числом, был вызван метод ToString (этот метод достался нам по наследству, но об этом узнаем позже). Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click ‘В текстовое поле помещаем информацию, конкатенированную из свойств экземпляра класса TextBox1.Text = p.FullName & " - " & p.PersonaId.ToString End Sub Проект готов к работе. Можно вводить различные имена наших персон, назначать им соответствующие персональные данные и просматривать их в окне формы. Конечно, в реальном приложении мы попытаемся сохранить всю введенную информацию, например, в базе данных, с тем, чтобы потом иметь к ней многократный доступ. Предложенный способ хранения данных в классе предельно прост, но имеет существенный недостаток, который заставляет описывать свойства класса другим способом (задание 2). Недостаток заключается в необходимости многократно повторять описание всевозможных проверок допустимости вводимых значений в свойства объектов. Предположим, необходимо проверять, что введенная информация в свойство FullName содержит только символы, но не цифры. Реализуем проверку для ввода информации непосредственно в интерфейсе проекта, для этого перепишем ввод данных в свойства экземпляра класса. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim s As String Dim ch As Char МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE s = InputBox("Введите имя сотрудника") For Each ch In s If Char.IsDigit(ch) Then MsgBox("вводите только символы") Exit sub ’Проверка недопустимости ввода цифровой информации. В случае ‘нарушения условия ввод прекращается End if Next p.FullName = s p.PersonaId = InputBox("Укажите его код") End Sub Проверка ввода допустимых символов выполнена следующим образом: введена дополнительная переменная ch типа Char (символы, 2 байта таблицы UniCode); для перебора всех символов строки s организован цикл с помощью конструкции For Each ch In s (строка представляет собой набор символов); класс Char имеет общие (Shared) методы, которые позволяют получить информацию о символе, мы воспользуемся методом Char.IsDigit(ch), который возвращает True, если символ является цифрой от 0 до 9; в случае, если метод Char.IsDigit(ch) вернет значение True появляется сообщение о недопустимости введенного символа и процедура ввода заканчивается. Примечание: С понятием «общий» или «shared метод» мы познакомимся позже, при изучении методов класса. Такие методы, являясь общими для всего класса, вызываются с именем класса, но не объекта класса. У класса Char есть несколько таких методов, перечислим некоторые из них, чтобы у вас была возможность потренироваться программировать проверки допустимости значений свойств объектов. Letter.IsDigit — возвращает True, если символ – цифра от 0 до 9; Letter.IsNumber — возвращает True, если символ – шестнадцатеричная цифра от 0 до F; Letter.IsLetter — возвращает True, если символ – буква от A до Z; Letter.IsLetterOrDigit — возвращает True, если символ – цифра от 0 до 9 или буква от A до Z; Letter.IsLower и IsUpper — возвращает True в зависимости от регистра символа; МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Letter.IsPunctuation — возвращает True, если символ классифицируется как знак пунктуации в таблице кодировки символов UNICODE; Letter.IsSymbol — возвращает True, если символ классифицируется как символ в таблице кодировки символов UNICODE (symbol); Letter.IsWhiteSpace — возвращает True, если символ классифицируется как символ пустого места в таблице кодировки символов UNICODE. Совершенно очевидно, что подобные проверки, если они необходимы, должны быть также инкапсулированы в описании свойств в самом классе. То есть, использование глобальных переменных (переменных с областью видимости Public) для описания свойств класса допустимо только в тех случаях, когда к свойствам класса можно обеспечить доступ без соблюдения особых мер предосторожности. Самостоятельно Добавьте в проект проверку на допустимые символы при вводе значения свойства P.PersonaId. Используйте для этого перечисленные выше свойства класса Char. Протестируйте полученные результаты. Задание 2. Описание свойств класса, как закрытых переменных Задача Обеспечить хранение свойств класса в закрытых переменных, доступ к которым регламентирован. Решение При описании свойств класса использовать ключевое слово Private и конструкцию Property. Обсуждение Применение ключевого слова Private перед именем переменной гарантирует, что эта переменная, будет доступна только внутри класса, то есть только собственные методы класса могут непосредственно изменять значения таких свойств. В этом случае для записи значения свойства в переменную и для чтения этого значения используются процедуры свойств Property. Доступ к значениям свойств класса внутри процедуры Property осуществляется с помощью блоков Get и Set. Блок Get предназначен для получения (считывания) значений свойств экземпляра класса, а блок Set – для присваивания (установки или записи). Интеллектуальный редактор Visual Studio.NET помогает описывать свойства через конструкции Property. После того, как вы начнете МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE описывать заголовок конструкции Property с указанием имени свойства, можно нажать клавишу ввода (Enter). Шаблон, который появится на экране, будет выглядеть следующим образом: Public Property ИмяСвойства() Get End Get Set(ByVal Value) End Set End Property Теперь осталось внести в этот шаблон описание доступа к конкретному свойству класса, например, описание свойства FullName класса Persona может выглядеть так: Public Class Persona Private _fullName As String Private _personaId As Integer Public Property FullName() Get ‘Вернуть значение переменной Return _fullName End Get Set(ByVal Value) _fullName = Value ‘Присвоить значение переменной End Set End Property Обратите внимание на имя переменной для хранения значения свойства и на имя самого свойства. Лучше, если они будут похожи, проще читается код класса. Обычно, названия свойств, объявленных как Private описывают с тем же именем, что и названия самих свойств, но добавляют префикс перед именем. Такой подход обеспечивает внешнюю схожесть имен при их фактическом отличии. Public Property PersonaID() Get Return _personaId End Get Set(ByVal Value) Me._personaId = Value End Set End Property End Class Предлагаемый шаблон Property предельно формализован, его можно подстроить под конкретные типы значений свойств. Public Property FullName() as string МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Get ‘Вернуть значение переменной Return _fullName End Get Set(ByVal Value as string) _fullName = Value ‘Присвоить значение переменной End Set End Property Public Property PersonaID() as integer Get Return _personaId End Get Set(ByVal Value as integer) Me._personaId = Value End Set End Property End Class Конструкция Property является по синтаксису обычной функцией, следовательно, можно добавить в ее сигнатуру типы возвращаемого значения и входных параметров с учетом тех конкретных типов, которые мы объявили при описании свойств класса. Теперь рассмотрим создание экземпляров класса Persona и работу с его свойствами. Переменная _fullName используется только для хранения значений свойства класса Person, а доступ к этим значениям выполняется с помощью процедур Get (положить) и Set (взять). Для обращения к свойству класса необходимо создать экземпляр класса и обратиться к свойству класса: Dim Person1 as New Persona Person1.FullName=”Табуреткин Вася” Экземпляр класса создается специальным методом New (конструктор класса), создание и применение которого мы рассмотрим далее. Теперь попробуем перенести проверку правильности ввода информации в свойство FullName непосредственно в описание этого свойства в рамках описания класса. Public Class Persona Private _fullName As String Private _personaId As Integer Public Property FullName() As String Get Return _fullName.ToUpper End Get МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Set(ByVal Value As String) Dim ch As Char For Each ch In Value If Char.IsDigit(ch) Then MsgBox("вводите только символы") Exit Property End If Next Me._fullName = Value End Set End Property Public Property PersonaID() as integer Get Return _personaId End Get Set(ByVal Value as integer) Me._personaId = Value End Set End Property End Class Протестируйте класс, свойства которого описаны как закрытые переменные. Обратите внимание на строчку кода Return _fullName.ToUpper в блоке Get описания свойства FullName. Конструкция Property используется не только для обращения к переменной _fullname, она позволяет выполнять любые программные действия, имеющие смысл, например, изменять регистр при выводе значения свойства. Другими словами, конструкцию Property необходимо использовать для всей необходимой обработки конкретного свойства класса. Самостоятельно Добавьте в описание свойства PersonaID ограничение на ввод чисел, не находящихся в диапазоне от 0 до 100. Протестируйте написанный код. Задание 3. Использование конструкторов класса Задача Создавать экземпляры класса с помощью конструкторов класса, которые позволят вводить начальные значения свойствам класса (инициировать их). МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Решение Описать в структуре класса специальные процедуры с именем New с входными параметрами или без них. Обсуждение Для создания экземпляров класса в объектно-ориентированном программировании используются специальные методы, называемые конструкторами класса. Конструкторы по синтаксису является процедурами. Конструкторы класса используются для инициирования свойств объекта класса. Конструктор может не описываться явно, в этом случае среда CLR создает его по умолчанию. До сих пор, при создании экземпляров класса мы использовали конструктор New, который нам предоставляла среда CLR. Пришло время научиться создавать собственные конструкторы. Конструктор может иметь или не иметь входные параметры. Конструкторов у класса может быть несколько (этот случай полиморфизма будет рассмотрен далее в теме 8). Приведем пример конструктора для экземпляров класса Persona. Public Sub New(ByVal Name As String, ByVal pID As integer) Me.FullName = Name Ключевое слово Me служит для указания текущего класса Me.PersonaID = pID End Sub Обратите внимание на использование ключевого слова (модификатора) Me. Это ключевое слово удобно применять для указания на текущий объект. Теперь при создании экземпляра класса следует вызывать конструктор класса, который имеет параметры: Dim Person1 as Persona = New Persona(“Петров”,567) Самостоятельно Добавьте в описание класса Persona свойство, позволяющее хранить дату рождения сотрудника. Разработайте еще один конструктор класса, при обращении к которому необходимо задать фамилию и дату рождения сотрудника. Протестируйте добавленное свойство и конструкторы класса. Задание 4. Ограничение доступа к свойствам класса Задача Создать свойства класса, доступные только для чтения хранящихся в них значений или только для записи. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Решение При описании свойств класса использовать (модификаторы) ReadOnly и WriteOnly. ключевые слова Обсуждение Добавив ключевое слово ReadOnly и удалив Set из блока Property, вы можете определить свойство, которое доступно только для чтения. Если вы добавите ключевое слово WriteOnly и удалите блок Get, вы можете получить свойство, доступное только для записи. Приведенный ниже код демонстрирует, каким образом можно создать такие свойства на примере свойств Password и PersonId. Свойство Password должно хранить пароль сотрудника, который можно только записать, но нельзя прочитать. Свойство PersonaID хранит личный номер сотрудника, который, наоборот, можно только просмотреть, но нельзя изменить (назначение этого номера происходит при записи о новом сотруднике однократно, редактированию не подлежит). Опишем новое свойство Password по уже известной схеме с применением конструкции Property. Public Class Persona Private _fullName As String Private _personaID As Integer Private _password As String Public Property FullName() As String Get Return _fullName.ToUpper End Get Set(ByVal Value As String) Dim ch As Char For Each ch In Value If Char.IsDigit(ch) Then MsgBox("вводите только символы") Exit Property End If Next Me._fullName = Value End Set End Property Public ReadOnly Property PersonaID() As Integer Get Return _personaID End Get End Property Public WriteOnly Property Password() As String МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Set(ByVal Value As String) _password = Value End Set End Property End Class Остается продумать: как будет записывать значение свойства PersonaID. Обычно это делается в конструкторе класса, то есть при создании объекта класса происходит присвоение значения свойствам, имеющим атрибут ReadOnly. В дальнейшем эти значения могут быть только прочитаны, но не изменены. Необходимо внести изменения в описание конструктора класса, так как теперь необходимо инициировать новое свойство Password и продумать каким образом будет формироваться свойство PersonaId. Предлагаем следующий вариант конструктора класса: Public Sub New(ByVal Name As String, ByVal pass As String) Dim randX As New Random Создаем экземпляр класса случайных чисел (датчика случайных чисел) Me.FullName = Name Ключевое слово Me служит для указания текущего класса Me.Password = pass _personaID = randX.Next(1, 100) Вызываем метод Next датчика случайных чисел, который позволяет получить число, находящееся в диапазоне от 1 до 100 End Sub Закрытое для чтения свойство Password может использоваться методами собственного класса, но недоступно для методов других классов. Самостоятельно Протестируйте свойства Password и PersonaID. Убедитесь, что можно только записать значение в свойство Password созданного объекта, но при попытке чтения возникает ошибка. При тестировании свойства PersonaID поработайте с датчиком случайных чисел. Класс Random генерирует псевдослучайные числа, то есть генерирует числа, которые статистически случайны только при последовательном просмотре. Работать с классом Random просто: нужно создать его экземпляр и вызвать метод Next или метод NextDouble. Метод NextDouble возвращает число с плавающей точкой и двойной точностью в диапазоне от 0,0 до 1,0-(не включая). Метод Next генерирует число, попадающее в указанный вами диапазон: Dim rand As New Random МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Получение случайного дробного числа от 0,0 до 1,0 Dim randDouble As Double = rand.NextDouble Получение случайного целого числа от 1 до 6 Dim randInt As Integer = rand.Next(1, 7) Получение еще одного случайного целого числа от 1 до 6 randInt = rand.Next(1, 7) Задание 5. Разделяемые переменные в классах Задача Создать переменную, которая будет общей, совместно используемой всеми объектами данного класса. Решение Чтобы объявить переменную совместно используемой, необходимо воспользоваться атрибутом (модификатором) Shared. Обсуждение Каждый создаваемый объект получает свою копию переменных, объявленных в классе, – к примеру, каждый объект класса Persona будет содержать свой набор переменных для свойств FullName, PersonaId, Password. Однако иногда возникает потребность создать переменную, которая будет общей, совместно используемой всеми объектами данного класса. Классический пример использования такой переменной – счетчик количества созданных объектов класса. В принципе, в этом случае можно воспользоваться глобальной переменной, но это будет нарушением логики парадигмы объектно-ориентированного программирования: количество экземпляров – это свойство класса, а не глобальное значение. К тому же, излишнее использование глобальных переменных ведет к проблемам в связи с засорением глобального пространства имен – все время придется придумывать новые имена переменных, чтобы они не конфликтовали с уже существующими именами. Чтобы объявить переменную совместно используемой, необходимо воспользоваться атрибутом (модификатором) Shared. Совместно используемой переменной можно сразу присвоить начальное значение при ее объявлении. Добавим в класс Persona переменную для подсчета количества созданных экземпляров и свойство, позволяющее пользователю узнать текущее значение этого счетчика. Переменную объявим с атрибутом (модификатором) Shared и присвоим ей начальное значение 0. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Public Class Persona Private _fullName As String Private _personaID As Integer Private _password As String Private Shared Count As Integer = 0 Public Shared ReadOnly Property Counting() As Integer Get Return Count End Get End Property Обратите внимание, что свойство Counting объявлено ReadOnly (только для чтения), так как запись значений переменной будет выполняться в конструкторах класса при создании очередного экземпляра. В каждый из имеющихся в структуре класса конструкторов класса необходимо добавить строку: Count += 1 Выполним это для нашего конструктора: Public Sub New(ByVal fullName As String, ByVal password As String) Dim randX As New Random Me.FullName = fullName Me.Password = password _personaID = randX.Next(1, 100) Count += 1 End Sub В созданные вами конструкторы (задание 3) также добавьте изменение значения свойства Count. Осталось добавить в класс Persona метод Dispose(), который будет изменять значений счетчика Count при удалении экземпляров класса Persona. Public Sub Dispose() Count -= 1 End Sub В конструкторы созданных вами классов также добавьте изменение значения свойства Count. Убедиться в работоспособности общего свойства Counting можно, например, следующим вызовом свойства: MsgBox(Person.Counting.ToString) в любом месте текущего проекта. Обратите внимание, что вызов свойства выполняется с именем класса, но не объекта класса, так как переменная обслуживает весь класс целиком, но не отдельные его экземпляры. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Самостоятельно Протестируйте свойство Counting, создав несколько экземпляров класса Persona. Примерный вид проекта для тестирования класса Persona может выглядеть, например, как на рис. 7.2. Проект включает командную кнопку и список ListBox для вывода свойства FullName созданных экземпляров класса Persona. Рис. 7.2. Пример формы для тестирования класса Persona Если вы будете использовать интерфейс (рис. 7.2), то в этом случае код тестирования может выглядеть следующим образом: Dim x As New Persona("Petrov", "parol") Dim y As New Persona("Sidorov") Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ListBox1.Items.Add(x.FullName) ListBox1.Items.Add(y.FullName) MsgBox(Person.Counting) End Sub Задание 6. Синхронизация элементов управления Задача Создать браузер записей, автоматически выполняющий обновление значений всех элементов управления в соответствии со значениями свойств текущего объекта. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Решение Создайте собственный класс для инкапсуляции данных, добавьте его экземпляры в класс ArrayList и используйте механизм связывания с данными, реализованный в .NET. Обсуждение Связывание с данными в .NET чаще всего применяется в приложениях ADO.NET, которые должны отображать одну или более записей из базы данных. Однако с той же легкостью его можно использовать и в приложениях других типов, заменив базу данных набором собственных объектов. Допустим, вы хотите отображать в нескольких элементах управления вашего проекта разные данные о сотрудниках. Для хранения данных о сотрудниках используем разработанный ранее класс Persona. Для хранения нескольких экземпляров Persona можно использовать динамический класс System.Collections.ArrayList. Класс ArrayList обычно используется для работы с массивами данных. Для добавления элементов в него служит метод Add, а для удаления – методы Remove, RemoveAt и RemoveRange (очень похоже на элемент управления ListBox, который вы могли использовать в задании 5). Dim Persons As New ArrayList Dim newPerson As New Persona("Дятлов", "D123") Persons.Add(newPerson) newPerson = New Persona("Сорокин", "S654") Persons.Add(newPerson) newPerson = New Persona("Рыжиков", "R875") Persons.Add(newPerson) newPerson = New Persona("Груздев", "G089") Persons.Add(newPerson) newPerson = New Persona("Волнушкин", "V456") Persons.Add(newPerson) Наконец, вы можете связать несколько элементов управления, размещенных в форме, с одним объектом ArrayList. Для связи элемента управления – списка нужно просто установить его свойство DataSource так, чтобы оно ссылалось на наш объект ArrayList. Кроме того, свойству DisplayMember списка следует присвоить имя свойства связанного объекта, которое требуется отображать. ListBox1.DataSource = Persons ListBox1.DisplayMember = "FullName" Многие другие элементы управления .NET, такие как кнопки, текстовые поля и надписи, не предоставляют особых возможностей связывания с данными, но они поддерживают связывание с данными МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE через набор DataBindings. Набор DataBindings позволяет связать любое свойство элемента управления со свойством собственного класса. Так вы можете связать свойство Text текстового поля со свойством Persona.FullName. После этого значение из объекта Persona будет автоматически выводиться в текстовое поле, а изменения текстового поля будут автоматически отражаться в объекте Persona. Следующий код выполняет связывание двух текстовых полей и свойств объектов класса Persona. TextBox1.DataBindings.Add("text", Persons, "FullName") TextBox2.DataBindings.Add("text", Persons, "PersonaId") Итоговая форма проекта показана на рис. 7.3. Элементы управления ListBox1, TextBox1 и TextBox2 синхронизированы. Таким образом, выбор в списке любого объекта приводит в выводу значений свойств этого же объекта и в текстовых полях. Рис. 7.3. Синхронизированные элементы управления для просмотра нескольких экземпляров класса Persona Самостоятельно Добавьте в форму разработанного проекта элемент управления для вывода даты рождения сотрудника. Синхронизируйте просмотр свойств у различных объектов. Задание 7. Создание класса Vector (свойства класса) Задача Выполнение действий над трехмерными векторами. Решение Создайте собственный класс вектора. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Обсуждение .NET Framework не поддерживает операции с векторами. Необходимо разработать пользовательский класс Vector. Предположительно структура класса может быть следующей: Public Class Vector 'Координаты вектора Private x, y, z As Double ‘При описании свойств с помощью конструкций Property необходимо осуществлять проверку на допустимость вводимой информации в переменные x, y, z 'Конструктор класса Public sub New() End Sub Методы класса Vector будут рассмотрены в следующей теме 'Сложение вектора с имеющимся вектором Public function Add() End Function End Class Самостоятельно Разработайте интерфейс для тестирования класса Vector. Добавьте в описание класса Vector разделяемую переменную для подсчета числа созданных экземпляров класса. Задание 8. Работа с простыми дробями Задача Выполнение математических действий над дробями без преобразования их в десятичную форму (которое может приводить к ошибкам округления). Решение Разработайте собственный класс простой дроби. Обсуждение .NET Framework не поддерживает действий над простыми дробями. Однако создать такой класс совсем несложно. Этот класс будет включать методы Add, Subtract, Multiply и DivideBy, которые будут запрограммированы при изучении следующей темы. В этом задании необходимо описать свойства класса и конструкторы класса. Предложения по именованию свойств класса следующие: МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Public Class Fractal 'Два компонента любой простой дроби Private Denominator As Integer Private Numerator As Integer ‘При описании свойств с помощью конструкций Property необходимо осуществлять проверку на допустимость вводимой информации в переменные Denominator, Numerator. Обратите внимание на тот факт, что знаменатель дроби должен быть отличен от нуля. 'Создание новой дроби Public sub New() End Sub Методы класса End Class Самостоятельно Разработайте интерфейс для тестирования класса Fractal. Добавьте в описание класса Fractal разделяемую переменную для подсчета числа созданных экземпляров класса. Задание 9. Печатающаяся строка Задача Получить анимационный эффект печатающейся строки регулируемыми параметрами (содержание и скорость печати). с Решение Разработайте собственный класс, например Words, который позволяет хранить любую строку текста и изменять скорость ее вывода в любом элементе управления формы. Обсуждение Прежде, чем создавать класс Words, необходимо обсудить, как работает элемент управления Timer. Таймеры используются для решения двух основных задач – измерения отрезков времени и синхронизации процессов с часами операционной системы. Таймеры – не визуальные элементы управления: при работе программы они не отображаются на форме. Таймеры имеют лишь два свойства – Enabled и Interval, а также поддерживают только одно событие Tick. Применительно к таймеру, значение свойства Enabled означает, таймер запущен (Enabled=True) или таймер остановлен (Enabled=False). МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Суть работы таймера сводится к тому, что он генерирует событие Tick каждые Interval миллисекунд. Перейдем к решению нашей задачи. Требуется организовать движение некоторой надписи с определенной скоростью. Такое движение можно организовать с применением таймера, у которого можно регулировать свойство Interval. То есть, при создании класса Words мы должны инкапсулировать в нем как минимум два свойства: одно – для хранения самой строки, другое – для хранения скорости ее вывода. Класс Words мог бы выглядеть, примерно, так: Public Class Words Public msg As String Public interval As Integer Public Sub New(ByVal message As String, ByVal interval As Integer) Me.msg = message Me.interval = interval End Sub End Class Спроектируем форму для исследования поведения экземпляров класса и возможностей элемента Timer (рис. 7.4). Обратите внимание, что элемент управления Timer1 – это не визуальный элемент, при конструировании формы этот элемент перетаскивается в нижнюю часть формы, но при запуске проекта элемент не будет виден. Добавим в форму код обработки командных кнопок и таймера. МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE Dim MyMessage As New Words("Изучайте языки программирования, это очень обогащает Ваш словарный запас", 200) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click If Button1.Text = "Старт" Then Timer1.Enabled = True Timer1.Interval = MyMessage.interval Button1.Text = "Стоп" Else Timer1.Enabled = False Button1.Text = "Старт" End If End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick ' Анимация слева направо Static c As Integer = 0 Label1.Text = MyMessage.msg.Substring(0, c) Me.Text = MyMessage.msg.Substring(0, c) c += 1 If c = MyMessage.msg.Length() + 1 Then c = 0 'Анимация справа налево Dim title2 As String = "Кнопка" Static i As Integer = title2.Length() Button2.Text = title2.Substring(0, i) i -= 1 If i = -1 Then i = title2.Length() End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click MsgBox("У нас все получится", "Программируйте, и все будет хорошо!") End Sub Не забудьте присвоить свойству text кнопки Button1 – значение «Старт», так как это значение используются в коде программы. Разберем, что мы написали. Кнопка с надписью Старт запускает таймер, при этом надпись Старт меняется на Стоп. При повторном нажатии надпись Стоп заменяется обратно на Старт. При этом происходит включение и выключение таймера (рис. 7.4). Вся работа по созданию эффекта происходит в событии таймера Tick. Далее идет использование объекта класса Words,. свойства которого мы МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ INTERNATIONAL BANKING INSTITUTE используем для организации выводимой в Label1 строки и для указания частоты обращения к таймеру. Рис. 7.4. Проект «Бегущая строка» в действии Самостоятельно Измените процесс вывода текста: пусть он не наращивается, а наоборот, уменьшается. В этом случае вам придется использовать еще один счетчик I, начальное значение которого пусть будет равным длине строки, а при каждом срабатывании таймера вычитайте один символ из строки. При достижении счетчиком значения 0 снова присвойте ему старое значение длины строки. Примените написанный код не к Label, а ко второй кнопке.