Принципы объектно-ориентированного программирования

         

Полиморфизм



Полиморфизм

По-моему, самое короткое и выразительное определение полиморфизма таково: это функциональная возможность, позволяющая старому коду вызвать новый. Это свойство ООП, пожалуй, наиболее ценно, поскольку дает вам возможность расширять и совершенствовать свою систему, не затрагивая существующий код.

Предположим, вам нужно написать метод, в котором для каждого объекта из набора Employee вызывается метод CakulatePay. Все просто, если зарплата рассчитывается одним способом: вы можете сразу вставить в набор тип нужного объекта. Проблемы начинаются с появлением других форм оплаты. Допустим, у вас уже есть класс Employee, реализующий расчет зарплаты по фиксированному окладу. А что делать, чтобы рассчитать зарплату контрактников — ведь это уже другой способ расчета! В случае с процедурным языком вам пришлось бы переделать функцию, включив в нее новый тип обработки, так как в прежнем коде такой обработки нет. А объектно-ориентированный язык благодаря полиморфизму позволяет делать различную обработку.

В нашем примере надо описать базовый класс


Employee, а затем создать производные от него классы для всех форм оплаты (упомянутых выше). Каждый производный класс будет иметь собственную реализацию метода CakulatePay. Здесь и начинается самое интересное. Возьмите указатель на объект, приведите его к типу-предку и вызовите метод этого объекта, а средства языка времени выполнения обеспечат вам, благодаря полиморфизму, вызов той версии этого метода, которая вам требуется. Поясним сказанное на примере.

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, и весь существующий код продолжит работу в своем первоначальном виде!



Содержание раздела