|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Визначення класів в програмі
Від використання готових
класів .NET Framework ми переходимо до визначення власних класів в
програмі. Код класу можна розмістити в окремому файлі за допомогою команди Project
> Add Class, як в Vb6, або ж просто ввести його в потрібному модулі —
наприклад, в стартовому модулі, що містить точку входу в консольне застосування.
VB .NET не
дивиться на те, скільки класів визначається в одному файлі. У більшості класів
визначаються один або два конструктори, властивості для читання і зміни стану
об'єкту, а також методи для виконуваних дій. Для прикладу візьмемо простий
клас Empl oyee з двома полями (ім'я і зарплата) і невелику тестову програму.
У класі визначаються дві властивості, доступних тільки для читання; ці властивості
повертають значення полів. Методи в цьому класі відсутні: 1 Module
Employeetestl 2 Sub Main() 3 Dim Tom As
New Employee("Tom". 100000) 4 Console.WriteLine(Tom.TheName
& "salary is " & Tom.Salary) 5 Console. Readline() 6 End
Sub 7 '
Визначення класу 8 Public
Class Employee 9
Private m_name As String 10
Private m_salary As Decimal 11 Public Sub
New(Byva1 sname As String.ByVal cursalary As Decimal) 12
m_name = Sname 13
m_salary = cursalary 14 End
Sub 15 Public Readonly
Property Thename()As String 16
Get 17
Return m_name 18 End
Get 19 End
Property 20 Public Readonly
Property Salary() As Decimal 21 .Get . 22
Return m_salary 23 End
Get 24 End
Property 25 End
Class 26 End Module
У рядках 2—6 визначається процедура Sub Main, використовувана компілятором як
точка входу. Якщо ця процедура вибрана як стартовий об'єкт (це відбувається
за умовчанням, але взагалі стартовий об'єкт вибирається в діалігвом
вікні Project Properties), вона відповідає за створення початкових екземплярів. Далі
створені об'єкти зазвичай створюють інші об'єкти у відповідь на отримання ними повідомлень.
Звичайно, в нашій простий програмі нічого такого не відбувається. Безпосереднє створення
об'єкту відбувається в рядку 3, що грає ключову роль в процесі тестування
програми. У цьому рядку при створенні нового об'єкту Empl oyee методу New передаються
два параметри — ім'я і початкова зарплата. У рядку 4 ми виводимо значення властивостей
Thename і Salагу, щоб переконатися в тому, що початковий стан створеного об'єкту
був заданий вірно. Клас Empl
oyee визначається в рядках 8-25. Як згадувалося вищим, для зручності тестування
код класу визначається в початковому модулі, хоча ми з таким же успіхом могли
скористатися командою Project > Add Class і виділити його в окремий файл. Давайте уважно розглянемо
кожен рядок у визначенні класу. У рядку 8 ключове слово Publiс є
атрибутом рівня доступу і визначає, кому дозволено створювати екземпляри
цього класу. У нашому прикладі клас оголошений відкритим, тому теоретично будь-який
охочий зможе створювати його екземпляри після компіляції — для цього в
програму досить включити посилання на збірку, що містить цей клас (складки
розглядаються в розділі 13). Щоб клас міг використовуватися тільки в рамках
нашого проекту і залишався недоступним для зовнішніх програм, ключове слово
Public слід замінити ключовим словом Friend. У рядках
9 і 10 визначаються закриті поля для зберігання інформації про стан об'єкту.
В черговий раз нагадаємо, що змінні завжди повинні оголошуватися закритими
(Private). У своїх визначеннях класів і модулів ми завжди починаємо імена полів
з префікса m_ або m. У
рядках 11-14 визначається конструктор, призначений для створення екземплярів
класу. Конструктор задає значення закритих полів екземпляра відповідно до значень
отриманих параметрів. У рядках
15-19 і 20-24 визначаються дві відкриті властивості, доступних тільки для читання.
Вони призначені для отримання інформації про поточний стан об'єкту. У приведеному
прикладі використано ключове слово Return, проте з таким же успіхом можна
було застосувати старий синтаксис з привласненням імені властивості: Get Thename = m_name End
Get Втім,
навіть в цій формі синтаксис процедури властивості дещо змінився в порівнянні
з Vb6 — зникли старі конструкції Property
Get/property Set. Наступна
версія програми показує, як зробити властивість Salary доступною для читання
і запису. Для цього досить видалити ключове слово Readonly і додати невеликий
фрагмент: Public Property
Salary()As Decimal Get Return m_salary
End Get Set(Byval Value As Decimal) m_salary
= Value End Set End
Property У цьому фрагменті перш
за все слід звернути увагу на читання нового значення властивості із
застосуванням ключового слова Value. Інакше кажучи, коли в програмі зустрічається
рядок виду Tom.Salary = 125000, параметру Value автоматично привласнюється
значення 125 000. Допустимо,
ми вирішили оголосити властивість Salary доступним тільки для читання і включити в
клас метод для підвищення зарплати. Метод оголошується як звичайна процедура
або функція. У нашому прикладі метод не повертає значення, тому вибір варто
зупинити на процедурі: Public Sub Raisesalary(Byval
Percent As Decimal) m_salary =(1 + Percent) * m_salary End Sub Члени класу
оголошуються з модифікаторами Public, Private або Friend. Ключове слово Pri
vate означає, що член класу використовується тільки усередині класу.
Атрибути рівня доступу і створення об'єктів
Атрибути
рівня доступу, встановлені для класу, управляють можливістю створення об'єктів
відповідного типу. Грубо кажучи, вони є віддаленим аналогом властивості
Instancing в Vb6, хоча для деяких значень Instancing доводиться додатково
враховувати рівень доступу конструктора. У таблиці. 4.5 описана відповідність між
властивістю Instancing Vb6 і комбінаціями атрибутів рівня доступу класу і конструктора. Таблиця
4.5.
Значення властивості Instancing і атрибути рівня доступу
Якщо клас використовується
як шаблон для створення однотипних об'єктів, програміст повинен мати
можливість послатися на поточний об'єкт, якому належить виконуваний код.
Зарезервоване слово Me завжди інтерпретується як об'єктна змінна, що
позначає поточний екземпляр. Застосування Me гарантує, що неоднозначна
конструкція буде інтерпретована в контексті поточного класу. Також
варто відмітити, що один з найпоширеніших (і найбезглуздіших) прикладів використання Me
зустрічається в ситуаціях на зразок наступної: Public
Class Point Private x As Integer Private у As Integer Public Sub New(Byval
x As Integer.ByVal у As Integer) Me.x = x Me.у = у End
Sub ' І так далі End
Class Запис Me.
x використовується для того, щоб відрізнити поле х екземпляра від параметра х, передаваного
при виклику методу New. Звичайно, проблема легко вирішується додаванням префікса
m_ перед ім'ям змінної класу, проте подібні конструкції часто використовуються
в С#; можливо, вони зустрінуться в програмі, супровід якої вам буде
доручено.
Метод
Raisesalary класу Employee можна зробити і поцікавіше. Припустимо, підвищення
зарплати до 10% відбуваються автоматично, але для великих сум потрібний спеціальний
пароль. У колишніх версіях VB такі завдання вирішувалися за допомогою необов'язкових
параметрів. Хоча ця можливість збереглася і в VB .NET, існує витонченіше рішення
з визначенням двох версій Raisesalary. Використовуючи можливість перевантаження
методів, ми визначаємо два разних методу для різних випадків. У
VB .NET синтаксис перевантаження методів дуже простий: для цього в програмі
просто визначаються два методи з однаковими іменами і різними параметрами. Проте ми настійно
рекомендуємо використовувати ключове слово Over! oads. По ньому користувачі вашої
коди дізнаються про те, що метод перевантажується навмисно, а не в результаті помилки.
У наступному фрагменті приведено дві версії методу Raisesalary, про яких мовилося
вище: Public Overloads Sub Raisesalary(Byval Percent As Decimal) If Percent >
0.1 Then ' Операція заборонена - необхідний пароль Console.WhteLineC'MUST
HAVE PASSWORD TO RAISE SALARY " & _ "MORE THAN
10*!!!!") Else X m_salary =(1
+ Percent) * m_salary End If End
Sub Public Overloads Sub Raisesalary(Byval
Percent As Decimal._ Byval Password
As Stqng) If
Password -"special Then m_salary = (1
+ Percent) * m_salary End If End Sub Нижче приведений
приклад класу Empl oyee з переобтяженим методом Rai sesalany, а також невелика
тестова програма. Звернете увагу: 10%-ний поріг не кодується в програмі,
а визначається у вигляді константи: Option Strict
On Module Modulel Sub Main() Dim Tom As New
Employee("Tom". 100000) Console.WhteLineCTom.TheName
& " has salary " & Tom.Salary) Tom.RaiseSalary(0.2d) ' Суфікс
D - ознака типу Decimal Console.WriteLine(Tom.TheName
& " still has salary " & Tom.Salary) Console. Whteline() Dim Sally As
New Employee("Sally", 150000) Console.WriteLine(Sally.TheName
& " has salary " & Sally.Salary) Sally.RaiseSalary(0.2d,"special") ' Суфікс
D - ознака типу Decimal Console.WriteLine(Sally.TheName
& "has salary "Ssally.Salary) Console. Writeline() Console.WriteLine("Please
press the Enter key") Console. Readline() End Sub End
Module Public
Class Employee Private m_name As String Private m_salary As Decimal Private Const
LIMIT As Decimal = 0.1d Public Sub New(Byval thename As String,byval cursalary As Decimal) m_name = thename m_salary = cursalary End
Sub Readonly Property
Thename()As String Get Return
m_name End Get ' End
Property Readonly Property
Salary()As Decimal Get Return m_salary End Get End
Property Public Overloads Sub Raisesalary(Byval Percent As Decimal) If Percent >
LIMIT Then ' Операція заборонена - необхідний пароль Console.WriteLine("MUST HAVE PASSWORD TO RAISE SALARY " & _ "MORE THAN
LIMIT!!!!") Else m_salary =(1
+Percent)*m_salary End If End Sub Public Overloads Sub Raisesalary(Byval Percent As Decimal._ Byval Password As String) If
Password = "special" Then m_salary =(1 + Percent) * m_salary End If End Sub End Class
Якщо у вашому класі не визначений
конструктор, VB .NET автоматично генерує для нього конструктор, що викликається без
аргументів. Робота цього конструктора зводиться до ініціалізації всіх полів
екземпляра значеннями за умовчанням. Такий конструктор називається конструктором за
умовчанням або безаргумєїтн'м конструктором. Якщо в класі
визначений хоч би один призначений для користувача конструктор, VB .NET не почне
генерувати конструктор за умовчанням. Ніщо не
заважає вам визначити в класі декілька конструкторів з різними рівнями доступу.
Наприклад, можна визначити абсолютно безпечний конструктор з атрибутом Public
і конструктор з атрибутом Friend, використання якого зв'язане з трохи більшим
ризиком. Звичайно, ці конструктори повинні викликатися з різними параметрами, оскільки
VB .NET розрізняє методи за списком параметрів, а не по модифікаторах рівня
доступу. Конструктори перевантажуються, як
і решта методів, проте при цьому не можна використовувати ключове слово
Overloads. Нижче приведений фрагмент оновленої версії класу Employee з конструктором,
що дозволяє задати значення нового поля. Public
Class Employee Private
m_name As String Private
m_nickname As String Private
m_salary As Decimal Public Sub Newcbyval
sname As String.ByVal cursalary As Decimal) m_name =
sname m_salary = cursalary End Sub Public SubNewcbyval
thename As String.ByVal nickname As String._ Byval cursalary
As Decimal) m_name =
thename m_nickname = nickname m_salary = cursalary End Sub Компілятор
вибирає другу версію конструктора лише в тому випадку, якщо при виклику передаються
два строкові параметри і один числовий. При передачі одного рядка і числа вибирається
перший конструктор. Перевантаження
конструкторів приводить до дублювання коди в програмі. Так, в приведеному вище
фрагменті значення m_name і fli_sa,lary привласнювалися в обох конструкторах.
У VB .NET для таких ситуацій передбачена спеціальна сокращенная
запис: конструкція Myclass.New викликає інший конструктор класу [ На момент
написання книги також можна було скористатися ключовим словом Me, але варіант
з Myclass є переважним. ]. Приклад: Public Sub New(Byval
sname As String.ByVal cursalary As Decimal) m_name =
Sname mjsalary
= cursalary End Sub Public Sub New(Byval
sname As String, Byval nickname As String._ Byval cursalary As Decimal) Myclass.Newt
sname.curSalary) m_nickname =nickName End Sub При виклику
іншого конструктора конструкцією Myclass. New порядок визначення конструкторів
в програмі не важливий. VB .NET вибирає конструктор за типом переданих параметрів
незалежно від його місця у визначенні класу.
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||