Третий принцип объектно-ориентированного программирования: поддержка полиморфизма в C#
Вспомните, что в базовом классе Employee определен метод по имени GiveBonus, который первоначально был реализован так (до его обновления с целью использования шаблона свойств):
public partial class Employee
{
public void GiveBonus(float amount) => _currPay += amount;
...
}
Поскольку метод 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);