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

ЖАНРЫ

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

 // но дочерние классы могут переопределить это поведение.

 public virtual void GiveBonus(float amount) {currPay += amount;}

 …

}

Чтобы в подклассе переопределить виртуальный метод, используется ключевое слово override. Например, SalesPerson и Manager могут переопределить GiveBonus так, как показано ниже (мы предполагаем, что PTSalesPerson переопределяет GiveBonus примерно так же, как SalesPerson),

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; // Вcе, что больше 200.

base.GiveBonus(amount * salesBonus);

}

}

public class Manager: Employee {

 // Менеджер в дополнение к денежному вознаграждению

 // получает некоторое число опционов.

public override void GiveBonus(float amount) {

// Прибавка к зарплате.

base.GiveBonus(amount);

// И получение опционов…

Random r = new Random;

numberOfOptions += (ulong)r.Next(500);

 }

 …

}

Обратите внимание на то, что переопределенный метод будет использовать поведение, принятое по умолчанию, если указать ключевое слово base. При этом нет необходимости снова реализовывать логику GiveBonus, а можно снова использовать (и, возможно, расширить) поведение родительского класса, принятое по умолчанию.

Также предположим, что Employee.DisplayStats был объявлен виртуально и переопределен каждым подклассом, чтобы учесть число продаж (для продавцов) и текущее состояние опционов (для менеджеров). Теперь, когда каждый подкласс может по-своему интерпретировать виртуальные методы, каждый экземпляр объекта ведет себя более независимо.

static void Main (string[] args) {

 // Лучшая система премиальных!

 Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);

 chucky.GiveBonus(300);

 chucky.DisplayStats;

 SalesPerson fran = new SalesPerson("Fran", 43, 93, 3000, "932-32-3232", 31);

 fran.GiveBonus(200);

 fran.DisplayStats;

}

Снова о ключевом слове sealed

Ключевое

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

Например, если (по некоторой причине) классу PTSalesPerson требуется разрешить расширение другими классами, но нужно гарантировать, чтобы эти классы не могли переопределять виртуальный метод GiveBonus, можно использовать следующий вариант программного кода.

// Этот класс можно расширить,

// но GiveBonus не может переопределяться производным классом.

public class PTSalesPerson: SalesPerson {

 …

 public override sealed void GiveBonus(float amount) {

 }

}

Абстрактные классы

В данный момент базовый класс Employee скомпонован так, что он может поставлять своим потомкам защищенные члены-переменные, а также два виртуальных метода (GiveBonus и DisplayStats), которые могут переопределяться производным классом. Все это хорошо, но данный вариант программного кода имеет один недостаток: вы можете непосредственно создавать экземпляры базового класса Employee.

// Что же это значит?

Employee X = new Employee ;

В данном примере единственной целью базового класса Employee является определение общих полей и членов для всех подклассов. Вероятно, вы не предполагали, что кто-то будет непосредственно создавать экземпляры класса, поскольку тип Employee (работник) является слишком общим. Например, если я приду к вам и скажу "Я работаю!", то в ответ я, скорее всего, услышу вопрос "Кем вы работаете?" (консультантом, инструктором, ассистентом администратора, редактором, представителем Белого Дома и т.п.).

Ввиду того, что многие базовые классы оказываются чем-то вроде "небожителей", для нашего примера лучше всего запретить возможность непосредственного создания новых объектов Employee. В C# это можно сделать программными средствами, используя ключевое слово abstract.

// Обозначение класса Employee, как абстрактного,

// запрещает непосредственное создание его экземпляров.

abstract public class Employee {…}

Если вы теперь попытаетесь создать экземпляр класса Employee, то получите ошибку компиляции.

// Ошибка! Нельзя создать экземпляр абстрактного класса.

Employee X = new Employee;

Превосходно! К этому моменту мы построили очень интересную иерархию служащих. Мы добавим новые функциональные возможности в это приложение немного позже, когда будем рассматривать правила классификации в C#. Иерархия типов, определенных на данный момент, показана на рис. 4.9.

Поделиться с друзьями: