Чтение онлайн

на главную - закладки

Жанры

C# для профессионалов. Том II

Ватсон Карли

Шрифт:

Для целей нашего примера будем предполагать, что бонус является некоторой постоянной величиной, которую можно определить при создании менеджера. Мы откажемся в данном случае выполнять какие-либо специальные вычисления, связанные с прибылью.

Как можно при создании кода в VB обновить наше приложение? Существуют два возможных подхода, но оба они имеют серьезные недостатки. Можно:

□ Написать новый класс

Manager

□ Изменить класс

Employee

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

Employee
и затем изменить эту копию кода. Проблема состоит в том, что
Employee
и
Manager
имеют такой большой объем общего кода, как весь код, связанный со свойствами
Name
,
CompanyName
и
Salary
. Дублирование одного и того же кода является опасным. Что произойдет, если в некоторый момент какая-то причина заставит изменить код? Плохой разработчик надеется не забыть внести одинаковые изменения в оба класса. Это самый простой способ создания ошибок. Другая проблема состоит в том, что теперь существуют два несвязанных класса
Employee
и
Manager
, с которыми должен иметь дело код клиента, что скорее всего сделает его написание затруднительным. (Хотя можно обойти эту проблему, помещая общие свойства в интерфейс и реализуя этот интерфейс в обоих классах
Employee
и
Manager
.)

Альтернативным способом является написание класса

Manager
и размещение объекта
Employee
внутри него как переменной с областью действия класса. Это решает проблему дублирования кода, но по-прежнему оставляет нас с двумя различными объектами, а также с неудобным, непрямым синтаксисом для вызова методов и свойств сотрудника (
objManager.objEmployее.Name
и т.д.).

Если выбрать модификацию модуля класса сотрудника, то по-видимому надо добавить дополнительное поле типа

Boolean
, которое указывает, является ли
Employee
менеджером или нет. Затем в соответствующих частях кода это
Boolean
будет проверяться в инструкции
if
, чтобы знать, что делать. Это решает проблему двух несвязанных классов — снова имеется только один класс. Однако это вносит новую трудность: как было специально сказано ранее, поддержку для менеджеров решено было добавить примерно год спустя. Это означает, что модуль класса
Employee
был по-видимому поставлен, протестирован, полностью отлажен и известно, что он работал правильно. В этой ситуации вряд ли возникнет желание обращаться к работающему коду, чтобы изменить его, учитывая связанный с этим риск внесения новых ошибок.

Другими словами, мы достигли точки, где VB не может предложить никакого удовлетворительного решения. Из заголовка этого раздела нетрудно сделать заключение, что C# предлагает способ решения этой проблемы с помощью использования наследования.

Мы уже видели, что наследование включает добавление или замену свойств классов. В предыдущем примере класс

SquareRootForm
добавил код к классу .NET
System.Windows.Forms.Form
. Он определил элементы управления для размещения в
SquareRootForm
как поля-члены, а также добавил обработчик событий. В примере
Employee
будут продемонстрированы как добавление, так и замена свойств базового класса, а также определен класс
Manager
, который является производным из класса
Employee
. Мы добавим поле и свойство, представляющие бонус, и заменен метод
GetMonthlyPayment
(для полноты также будет заменен метод
ToString
, чтобы он выводил бонус вместе с именем и зарплатой). Все это означает, что будет получен отдельный класс. Но при этом не потребуется дублировать никакой код и вносить большие изменения в класс
Employee
. Может показаться, что по-прежнему существует проблема двух различных классов, что делает более трудным написание клиентского кода, но, как будет продемонстрировано позже, C# имеет ответ и на это.

Наследование от класса Employee

Прежде чем определить класс

Manager
, необходимо внести одно маленькое изменение в классе
Employee
:

public virtual decimal GetMonthlyPayment {

 return salary/12;

}

что сделает метод

GetMonthlyPayment
виртуальным (
virtual
). Это способ, которым C# сообщает, что данный метод в принципе может быть переопределен.

Можно подумать, что это означает изменение базового класса, что противоречит тезису о ненужности изменения базового класса. Однако добавление ключевого слова

virtual
на самом деле
не является изменением, которое влечет за собой риск новых ошибок — при подходе VB необходимо было действительно переписать реализации нескольких методов. Кроме того, обычно при создании классов в C# заранее планируется, какие методы являются подходящими для переопределения. Если бы это был пример из реальной жизни, то метод
GetMonthlyPayment
почти наверняка объявлялся бы виртуальным, поэтому на самом деле можно добавить класс
Manager
, не делая никаких изменений в классе
Employee
.

Класс Manager

Теперь можно определить класс

Manager
:

class Manager : Employee {

 private decimal bonus;

 public Manager(string name, decimal salary, decimal bonus) : base(name, salary) {

this.bonus = bonus;

 }

 public Manager(string name, decimal salary) : this(name, salary, 100000M) {

 }

 public decimal Bonus {

get {

return bonus;

}

 }

 public override string ToString {

return base.ToStrint + ", bonus: " + bonus;

 }

 public override decimal GetMonthlyPayment {

return base.GetMonthlyPayment + bonus/12;

 }

}

Помимо почти завершенной реализации класса

Employee
, который был унаследован,
Manager
содержит следующие члены:

□ Поле

bonus
, которое будет использоваться для хранения бонуса менеджера, и соответствующее свойство.

□ Перезагруженный метод

GetMonthlyPayment
, а также новую перегруженную версию метода
ToString
.

□ Два конструктора.

Поле

bonus
и соответствующее свойство
Bonus
не требуют дальнейших обсуждений. Однако мы внимательно рассмотрим переопределенные методы и новые конструкторы, так как они будут иллюстрировать важные свойства языка C#.

Переопределение метода

Переопределенная версия метода

GetMonthlyPayment
является достаточно простой. Отметим, что она помечена ключевым словом
override
для сообщения компилятору, что мы переопределяем метод базового класса, как это делалось с методом
Employee.ToString
:

public override decimal GetMonthlyPayment {

 return base.GetMonthlyPayment + bonus/12;

}

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

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

public override decimal GetMonthlyPayment {

 return (Salary + bonus)/12;

}

но, чтобы показать использование ключевого слова

base
, был выбран другой вариант. В связи с этим есть одно действие, которое мы не смогли бы сделать:

public override decimal GetMonthlyPayment {

 return (salary + bonus)/12; // неправильно

}

Код выглядит почти так же, как предыдущая версия, кроме того, что поле

salary
используется непосредственно, а не через свойство
Salary
. Можно предположить, что это более эффективное решение, поскольку фактически убирается вызов метода. Но компилятор будет инициировать ошибку, так как поле
salary
объявлялось как
private
(закрытое). Этот означает, что ничему вне класса
Employee
не разрешается видеть это поле. Даже производные классы не знают о закрытых полях базового класса.

Поделиться:
Популярные книги

Начальник милиции. Книга 4

Дамиров Рафаэль
4. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 4

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Тисса горит

Иллеш Бела
Проза:
историческая проза
советская классическая проза
5.00
рейтинг книги
Тисса горит

Система Возвышения. (цикл 1-8) - Николай Раздоров

Раздоров Николай
Система Возвышения
Фантастика:
боевая фантастика
4.65
рейтинг книги
Система Возвышения. (цикл 1-8) - Николай Раздоров

Пышка и Герцог

Ордина Ирина
Фантастика:
юмористическое фэнтези
историческое фэнтези
фэнтези
5.00
рейтинг книги
Пышка и Герцог

Идеальный мир для Лекаря 6

Сапфир Олег
6. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 6

Случайная свадьба (+ Бонус)

Тоцка Тала
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Случайная свадьба (+ Бонус)

Ученик

Губарев Алексей
1. Тай Фун
Фантастика:
фэнтези
5.00
рейтинг книги
Ученик

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Бастард Императора. Том 8

Орлов Андрей Юрьевич
8. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 8

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Страж Тысячемирья

Земляной Андрей Борисович
5. Страж
Фантастика:
боевая фантастика
альтернативная история
фэнтези
5.00
рейтинг книги
Страж Тысячемирья

Полное собрание сочинений. Том 24

Л.Н. Толстой
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Полное собрание сочинений. Том 24

Идеальный мир для Лекаря 4

Сапфир Олег
4. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 4