...
}
Поскольку метод
GiveBonus()
был определен с ключевым словом
public
, бонусы можно раздавать продавцам и менеджерам (а также продавцам с частичной занятостью):
Console.WriteLine("***** The Employee Class Hierarchy *****\n");
// Выдать каждому сотруднику бонус?
Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);
chucky.GiveBonus(300);
chucky.DisplayStats();
Console.WriteLine();
SalesPerson fran = new SalesPerson("Fran", 43, 93, 3000, "932-32-3232", 31);
fran.GiveBonus(200);
fran.DisplayStats();
Console.ReadLine();
Проблема с текущим проектным решением заключается в том, что открыто унаследованный метод
GiveBonus()
функционирует идентично для всех подклассов. В идеале при подсчете бонуса для штатного продавца и частично занятого продавца должно приниматься во внимание количество продаж. Возможно, менеджеры вместе с денежным вознаграждением должны получать дополнительные фондовые опционы. Учитывая это, вы однажды столкнетесь с интересным вопросом: "Как сделать так, чтобы связанные типы реагировали по-разному на один и тот же запрос?". Попробуем найти на него ответ.
Использование ключевых слов virtual и override
Полиморфизм предоставляет подклассу способ определения собственной версии метода, определенного в его базовом классе, с применением процесса, который называется переопределением метода. Чтобы модернизировать текущее проектное решение, необходимо понимать смысл ключевых слов
virtual
и
override
. Если базовый класс желает определить метод, который
может быть (но не обязательно) переопределен в подклассе, то он должен пометить его ключевым словом
virtual
:
partial class Employee
{
// Теперь этот метод может быть переопределен в производном классе.
public virtual void GiveBonus(float amount)
{
Pay += amount;
}
...
}
На заметку! Методы, помеченные ключевым словом
virtual
, называются виртуальными методами.
Когда подкласс желает изменить реализацию деталей виртуального метода, он прибегает к помощи ключевого слова
override
. Например, классы
SalesPerson
и
Manager
могли бы переопределять метод
GiveBonus()
, как показано ниже (предположим, что класс
PtSalesPerson
не будет переопределять
GiveBonus()
, а потому просто наследует его версию из
SalesPerson
):
using System;
class SalesPerson : Employee
{
...
// Бонус продавца зависит от количества продаж.
public override void GiveBonus(float amount)
{
int salesBonus = 0;
if (SalesNumber >= 0 && SalesNumber <= 100)
salesBonus = 10;
else
{
if (SalesNumber >= 101 && SalesNumber <= 200)
salesBonus = 15;
else
salesBonus = 20;
}
base.GiveBonus(amount * salesBonus);
}
}
class Manager : Employee
{
...
public override void GiveBonus(float amount)
{
base.GiveBonus(amount);
Random r = new Random();
StockOptions += r.Next(500);
}
}
Обратите внимание, что каждый переопределенный метод может задействовать стандартное поведение посредством ключевого слова
base
.
Таким образом, полностью повторять реализацию логики метода
GiveBonus()
вовсе не обязательно, а взамен можно повторно использовать (и расширять) стандартное поведение родительского класса.
Также предположим, что текущий метод
DisplayStats()
класса
Employee
объявлен виртуальным:
public virtual void DisplayStats()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("Id: {0}", Id);
Console.WriteLine("Age: {0}", Age);
Console.WriteLine("Pay: {0}", Pay);
Console.WriteLine("SSN: {0}", SocialSecurityNumber);
}
Тогда каждый подкласс может переопределять метод
DisplayStats()
с целью отображения количества продаж (для продавцов) и текущих фондовых опционов (для менеджеров). Например, рассмотрим версию метода
DisplayStats()
из класса
Manager
(класс
SalesPerson
реализовывал бы метод
DisplayStats()
в похожей манере, выводя на консоль количество продаж):