- •Лекция 2. С# и объектно-ориентированное программирование Формальное определение класса в с#
- •Ссылки на самого себя
- •Определение открытого интерфейса по умолчанию
- •Указание области видимости на уровне типа: открытые и внутренние типы
- •Столпы объектно-ориентированного программирования
- •Инкапсуляция
- •Наследование: отношения «быть» и «иметь»
- •Полиморфизм: классический и для конкретного случая
- •Средства инкапсуляции в с#
- •Реализация инкапсуляции при помощи традиционных методов доступа и изменения
- •Второй способ инкапсуляции: применение свойств класса
- •Поддержка наследования в с#
- •Применение модели включения-делегирования
- •Поддержка полиморфизма в с#
- •Абстрактные классы
- •Принудительный полиморфизм: абстрактные методы
- •Приведение типов в с#
- •Приведение числовых типов
- •Обработка исключений
- •Жизненный цикл объектов
- •Завершение ссылки на объект
- •Интерфейс iDisposable
- •Взаимодействие со сборщиком мусора
Поддержка полиморфизма в с#
Предположим, что в базовом классе Employee определен метод GiveBonus( ) — поощрить:
// В классе Employee определен новый метод для поощрения сотрудников
public class Employee
{
public void GiveBonus(float amount)
{
currPay += amount;
}
. . . .
}
Поскольку этот метод определен в базовом классе как publiс, вы теперь можете поощрять продавцов и менеджеров:
// Поощрения объектам производных классов
Manager chucky = new Manager(“Chucky", 92, 100000, "333-23-2322", 9000);
Chucky.GiveBonus(300);
Chucky.DisplayStats( );
Salesperson fran = new SalesPerson("Fran", 93, 3000, "932-32-3232", 31);
Fran.GiveBonus(200);
Fran.DisplayStats( );
.
Проблема заключается в том, что унаследованный метод GiveBonus( ) пока работает абсолютно одинаково в отношении объектов обоих производных клас-— и объектов Salesperson, и объектов Manager. Однако, конечно, было бы лучше, чтобы для объекта каждого класса использовался свой уникальный вариант метода. Например, при поощрении продавцов можно учитывать их объем продаж. Менеджерам помимо денежного поощрения можно выдавать дополнительные опционы на акции. Поэтому задачу можно сформулировать так: «Как заставить один и тот же метод по-разному реагировать на объекты разных классов?»
Для решения этой задачи в С# предусмотрено понятие полиморфизма. Полиморфизм позволяет переопределять реакцию объекта производного класса на метод, определенный в базовом классе. Для реализации полиморфизма в нашем приложении мы воспользуемся ключевыми словами С#: virtual и override. Если базовый класс определяет метод, который должен быть замещен в производном классе, этот метод должен быть объявлен как виртуальный (конечно, при помощи ключевого слова virtual):
public class Employee
{
// Для метода GiveBonus( ) предусмотрена реализация по умолчанию.
// однако он может быть замещен в производных классах
public virtual void GiveBonus(float amount)
{
currPay += amount;
}
. . . .
}
Если вы хотите переопределить виртуальный метод, необходимо заново определить метод в производном классе, использовав ключевое слово override:
public class Salesperson : Employee
{
// На размер поощрения продавцу будет влиять объем его продаж
public override void GiveBonus(float amount)
{
int salesBonus = 0;
if(numberOfSales >= 0 && numberOfSales <=100)
salesBonus = 10;
else if(numberOfSales >= 101 && numberOfSales <= 200)
salesBonus = 15;
else
salesBonus = 20; // Для объема продаж больше 200
base.GiveBonus(amount * salesBonus);
}
. . . .
}
public class Manager Employee
{
private Random r = new Random( );
// Помимо денег менеджеры также получают некоторое количество опционов
// на акции
public override void GiveBonus(float amount)
{
// Деньги: увеличиваем зарплату
base.GiveBonus(amount);
// Опционы на акции: увеличиваем их количество
numberOfOptions += (ulong)r.Next(500);
}
. . . .
}
Обратите внимание, что в определении каждого из замещенных методов используется вызов этого же метода базового класса. Таким образом, нет необходимости заново определять всю логику замещенного метода в производном классе: вполне достаточно воспользоваться вариантом метода по умолчанию, определенном в базовом классе, дополнив его нужными вам действиями.
Метод Employee.DisplayStats( ) у нас также определен как virtual, и он замещен в производных классах таким образом, чтобы показывать текущий объем продаж, если речь идет о продавце, или количество опционов,-имеющееся в настоящее время в распоряжении менеджера. Теперь, когда для каждого из производных классов определены собственные варианты этих двух методов, объекты разных классов ведут себя по-разному:
// Улучшенная система поощрений!
Manager chucky = new Manager("Chucky", 92, 100000, "333-23-2322", 9000);
chucky.GiveBonus(300);
chucky.DisplayStats( );
Salesperson fran = new SalesPerson(“Fran", 93, 3000, "932-32-3232", 31);
fran.GiveBonus(200);
fran.DisplayStats( );
Мы с вами научились использовать полиморфизм для переопределения поведения производных классов. Однако, как, наверное, вы догадываетесь, возможности полиморфизма этим далеко не исчерпываются.