По-моему, самое короткое и выразительное определение полиморфизма таково: это функциональная возможность, позволяющая старому коду вызвать новый. Это свойство ООП, пожалуй, наиболее ценно, поскольку дает вам возможность расширять и совершенствовать свою систему, не затрагивая существующий код.
Предположим, вам нужно написать метод, в котором для каждого объекта из набора
Employee
вызывается метод
CakulatePay.
Все просто, если зарплата рассчитывается одним способом: вы можете сразу вставить в набор тип нужного объекта. Проблемы начинаются с появлением других форм оплаты. Допустим, у вас уже есть класс
Employee,
реализующий расчет зарплаты по фиксированному окладу. А что делать, чтобы рассчитать зарплату контрактников — ведь это уже другой способ расчета! В случае с процедурным языком вам пришлось бы переделать функцию, включив в нее новый тип обработки, так как в прежнем коде такой обработки нет. А объектно-ориентированный язык благодаря полиморфизму позволяет делать различную обработку.
В нашем примере надо описать базовый класс
using System;
class Employee
{
public Employee(string firstName, string lastName, int age, double payRate)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.payRate = payRate; }
protected string firstName;
protected string lastName;
protected int age;
protected double payRate;
public virtual double CalculatePay(int hoursWorked)
{
Console.WriteLine("Employee.CalculatePay"); return 42; // произвольное число
} >
class SalariedEmployee : Employee {
public SalariedEmployee(string firstName, string lastName,
int age, double payRate) : base(firstName, lastName, age, payRate) {}
public override double CalculatePay(int hoursWorked) {
Console.WriteLine("SalariedEmployee.CalculatePay"); return 42; // произвольное число } } .
class ContractorEmployee : Employee {
public ContractorEmployee(string firstName, string lastName, int age, double payRate)
: base(firstName, lastName, age, payRate)
<}
public override double CalculatePay(int hoursWorked) {
Console.WriteLineC'ContractorEmployee.CalculatePay");
return 42; // произвольное число } }
class HourlyEmployee : Employee {
public HourlyEmployee(string firstName, string lastName, int age, double payRate)
: base(firstName, lastName, age, payRate)
{}
public override double CalculatePay(int hoursWorked) <
Console.WriteLine("Hou rlyEmployee.CalculatePay");
return 42; // произвольное число > }
class PolyApp {
protected Employee[] employees;
protected void LoadEmployeesQ
{
Console.WriteLine("Загрузка информации о сотрудниках...");
// В реальном приложении эти сведения мы // возьмем, наверное, из базы данных, employees = new Employee[3];
employees[0] = new SalariedEmployee ("Amy", "Ariderson", 28, 100);
employees[1] = new ContractorEmployee ("John", "Maffei", 35, 110); employees[2] = new HourlyEmployee ("Lani", "Ota", 2000, 5);
Console. Writel_ine( "\n"); }
protected void CalculatePayO .
{
foreach(Employee emp in employees)
<
emp.CalculatePay(40);
} }
public static void Main()
{
PolyApp app = new PolyAppQ;
app.LoadEmployees(); app. CalculatePayO; } }
В результате компиляции и запуска этого приложения будут получены такие результаты:
c:\>PolyApp
Загрузка информации о сотрудниках...
SalariedEmployee.CalculatePay ContractorEmployee.CalculatePay HourlyEmployee.CalculatePay
Полиморфизм имеет минимум два плюса. Во-первых, он позволяет группировать объекты, имеющие общий базовый класс, и последовательно (например, в цикле) их обрабатывать. В рассмотренном случае у меня три разных типа объектов
(SalariedEmployee, ContractorEmployee
и
Hourly-Employee),
но я вправе считать их все объектами
Employee,
поскольку они произведены от базового класса
Employee.
Поэтому их можно поместить в массив, описанный как массив объектов
Employee.
Во время выполнения вызов метода одного из этих объектов будет преобразован, благодаря полиморфизму, в вызов метода соответствующего производного объекта.
Второе достоинство я упоминал в начале этого раздела: старый код может использовать новый код. Заметьте: метод
PolyApp.Calculate Pay
перебирает в цикле элементы массива объектов
Employee.
Поскольку объекты приводятся неявно к вышестоящему типу
Employee,
а реализация полиморфизма во время выполнения обеспечивает вызов надлежащего метода, то ничто не мешает нам добавить в систему другие производные формы оплаты, вставить их в массив объектов
Employee,
и весь существующий код продолжит работу в своем первоначальном виде!