|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Звернення
до функціональності базового класу
У
VB .NET існує модифікатор Protected, який автоматично
надає доступ з похідних класів до відповідного члена класу, будь то метод
або змінна класу. Виникає спокуса скористатися цим модифікатором і
оголосити всі поля базового класу з рівнем доступу Protected, щоб похідні
класи могли легко і швидко працювати з ними. Не піддайтеся спокусі! Хороший
стиль проектування вимагає, щоб модифікатор Protected використовувався тільки для методів,
але не для змінних. Інакше порушується інкапсуляція і втрачається можливість
перевірки даних там, де вона повинна відбуватися — в базовому класі. Як і в
реальному житті, тут діє хороший принцип «довіряй, але перевіряй». Наприклад,
в початкове визначення класу Employee входять властивості з наступними сигнатурами: Public Readonly Property Thename() As String Public Readonly
Property Salary() As Decimal Таким чином,
доступ до цих властивостей дозволений всім класам. Щоб обмежити доступ до властивостей
класами, похідними від Empl oyee, заміните модифікатор Publ ic на Protected. У таблиці. 5.1 перераховані
різні модифікатори рівня доступу, що привласнюються членам класів
в ієрархії спадкоємства. Як було
сказано вище, функції (але не поля!) з модифікаторами Protected і Protected Friend
поширені достатньо широко, оскільки вони запобігають доступу до захищених
членів з боку зовнішньої коди. При
використанні Protected виникає вельми цікава каверза. На щастя, компілятор
вчасно попередить вас про можливі проблеми. Розглянемо конкретний приклад:
допустимо, у вас є клас Geekfest з методом Boast, який намагається звернутися
до властивості Salary класу Programmer (що кінець кінцем означає доступ до властивості
Sal агу базового класу Empl oyee). Нижче приведений зразковий вид програми: Public
Class Geekfest Private m_programmers()
As Programmer Sub New(Byval
Programmers() As Programmer) m_programmers = Programmers End Sub Public Function
Boast(Byval ageek As Programmer) As String Return "Неу my salary is " & ageek.Salary End Function End Class "left"> Таблиця
5.1. Модифікатори рівня доступу при
спадкоємстві
Також допустимо,
що в клас Empl oyee входить властивість Sal агу, доступне тільки для читання і
помічене модифікатором Protected замість Public: Protected Readonly
Property Salary() As Decimal Get Return Myclass.m_Salary End Get End
Property В результаті
компілятор видає повідомлення про помилку: C:\vb net book\chapter 5\examplel\examplel\moduleld.vb(19): 'Examplel. Modulel.Employee. Protected Readonly Property Salary() As Decimal'
is Protected.and is not accessible in this context. Хоча клас
Programmer володіє доступом до захищеної властивості Salary в своєму коді,
об'єкти Programmer не мають доступу до цього методу за межами коди
класу Programmer. Підведемо підсумок: Звернення
до Protected-методам базового класу можливо тільки з об'єктів похідного
класу, але не із зовнішніх посилань на ці об'єкти за межами похідного класу.
Перевизначення
властивостей і методів
У нашому прикладі,
де програміст автоматично отримує 6-процентне підвищення зарплати замість
5-процентного, необхідно змінити поведінку методу Raisesalary і відобразити в
ній автоматичну надбавку. Це називається перевизначенням функції.
На відміну
від багатьох об'єктно-орієнтованих мов синтаксис VB .NET чітко показує,
що метод базового класу повинен перевизначатися в похідному класі. Для
цього використовуються два спеціальні ключові слова.
Нижче приведений
зразковий вид базового класу Employee з методом Raisesalary, який може
перевизначатися в похідних класах Programmer, Manager і так далі Ключові
рядки коди виділені жирним шрифтом: Option
Strict On 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 Public Readonly
Property Thename()As String Get Return
m_name End Get
End Property Public Readonly
Property Salary()As Decimal Get Return Myclass.m_Salary End Get
End Property Public Overridable
Overloads Sub Raisesalary(Byval Percent As Decimal) If Percent >
LIMIT Then '
Операція заборонена - необхідний пароль Console.WriteLine('NEED
PASSWORD TO RAISE SALARY MORE " & _ "THAN LIMIT!!!!")
Else m_salary =(1 + Percent) * m_salary End If End
Sub Public Overridable
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 Необов'язкове
ключове слово Overloads, згадуване в розділі 4, указує на те, що в класі
визначено декілька версій Raisesalary. У нашій моделі
зарплата програміста підвищується викликом спеціалізованої версії методу Raisesalary.
Похідний клас Programmer приведений нижче (як завжди, ключові рядки виділені
жирним шрифтом): Public
Class Programmer Inherits
Employee Public Sub New(Byval
thename As String, Byval cursalary As Decimal) Mybase.New(thename, cursalary) End
Sub Public Overloads
Overrides Sub Raisesalarycbyval Percent As Decimal) Mybase.RaiseSalary(1.2d *Percent."special") End Sub End Class Звернете
увагу, яким компактним вийшов похідний клас — велика частина функціональності
залишилася незмінною, тому ми просто успадковуємо її від базового класу! У приведеній нижче
процедурі Sub Main компілятор генерує виклик правильної версії методу Rai
sesal ary (з 20-процентною надбавкою) для об'єкту sal 1у, Programmer, що відноситься
до класу: Sub Main() Dim sally As New Programmed"sally". 150000d) sally.RaiseSalary(0.1d) ' З урахуванням надбавки для програмістів Console.WriteLine(sally.TheName & " salary is now " & sally.Salary()) Console.ReadLine() End
Sub Підведемо
підсумок:
Ключове слово
VB .NET Notlnheritable повністю забороняє спадкоємство від класу. Як правило,
спадкоємство забороняється для класів, що виконують дуже важливі функції,
які у жодному випадку, на повинні змінюватися. Багато класів .NET Framework (такі,
як String) помічені ключовим словом Notlnheritable саме з цієї причини. Втім,
якщо потрібно заборонити перевизначення лише одного члена класу, немає
чого забороняти спадкоємство для всього класу; досить помітити ключовим
словом Notoverridable потрібний член класу.
Іноді при
перевизначенні методу або властивості виникає необхідність викликати версію базового
класу. Допустимо, імені кожного програміста в класі Programmer повинен передувати
почесний титул «Code Guru». Ключове слово Mybase дозволяє звернутися
до відкритої властивості Thename базового класу в похідному класі: Public Overrides
Readonly Property Thename() As String Get Return "Code
Guru " & Mybase.TheName() End Get End Property Врахуйте, що
ключове слово Mybase володіє рядом обмежень:
З Mybase
тісно пов'язано інше ключове слово — Myclass. Воно гарантує, що навіть у разі
перевизначення буде викликаний метод, визначений в поточному класі, а не якась
з його перевизначених версій в похідних класах. На ключове слово Mycl
ass розповсюджуються ті ж обмеження, що і на ключове слово Mybase, про яке
згадувалося в попередньому розділі.
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||