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

         

какие члены базового класса наследуются



ПРИМЕЧАНИЕ

Вопрос, какие члены базового класса наследуются производными классами, решается в С# через модификаторы доступа, применяемые при описании члена. Подробнее об этом см. главу 5, мы же пока будет считать, что производный класс наследует все члены своего базового класса.

Чтобы понять, когда и как применять наследование, вернемся к примеру EmployeeApp. Допустим, в компании есть служащие с разными типами оплаты труда: постоянный оклад, почасовая оплата и оплата по договору. Хотя у всех объектов Employee должен быть одинаковый интерфейс, их внутреннее функционирование может различаться. Например, метод CalculatePay для служащего на окладе будет работать не так, как для контрактника. Однако для ваших пользователей важно, чтобы интерфейс CalculatePay не зависел от того, как считается зарплата.

У новичка в ООП, вероятно, появится вопрос: "А нельзя ли здесь обойтись без объектов? Введи в структуру EMPLOYEE член, описывающий тип оплаты, и напиши функцию вроде этой:

Double CalculatePay(EMPLOYEE" pEmployee, int IHoursWorked) {



// Проверяем указатель pEmployee.

if (pEmployee->type == SALARIED) {

// Вычисляем заработок для служащего на окладе. } else if (pEraployee->type == CONTRACTOR)

{

// Вычисляем заработок по контракту. }

else if (pEmployee->type == HOURLY) <

// Вычисляем почасовой заработок. }

else {

// Выполняем иную обработку. }

// Возвращаем значение, полученное от одного из // вышестоящих операторов. }

В этом коде есть две проблемы. Во-первых, успешное выполнение функции тесно связано со структурой EMPLOYEE. Как я уже говорил, подобная связь очень нежелательна, поскольку любое изменение структуры потребует модификации этого кода. Как объектно-ориентированный программист, вы меньше всего захотите "грузить" пользователей вашего класса подробностями, в которых непосвященному разобраться трудно. Это все равно, как если бы производитель автомата по продаже газировки, перед тем как вам набрать стакан воды, потребовал от вас знания работы внутренних механизмов автомата.

Во-вторых, такой код нельзя задействовать повторно. Тот, кто понимает, что наследование способствует повторному использованию кода, теперь по достоинству оценит классы и объекты. Так, в нашем примере достаточно описать в базовом классе те члены, которые будут функционировать независимо от типа оплаты, а любой производный класс унаследует функции базового класса, добавив к ним что-то свое. Так это выглядит на С#:

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 double CalculatePay(int hoursWorked) {

// Здесь вычисляется зарплата.

return (payRate * (double)hoursWorked); } }

class SalariedEmployee : Employee

{

public string SocialSecurityNumber;

public void CalculatePay (int hoursWorked)

{

// Вычисляем заработок постоянного служащего.

} }

class ContractEmployee : Employee {

public string FederalTaxId;

public void CalculatePay (int hoursWorked)

{

// Вычисляем заработок для контрактника.

}

}

Отметим три важных момента, вытекающих из данного примера.
  • В базовом классе Employee описана строковая переменная Employeeld, которая наследуется и классом SalariedEmployee, и классом Contract-Employee. Оба производных класса получили эту переменную автоматически как наследники класса Employee.
  • Каждый из производных классов реализует свою версию CalculatePay. Вы видите, что они оба унаследовали этот интерфейс, и хотя реализация этих функций различна, пользовательский код остался прежним.
  • Оба производных класса в дополнение к членам, унаследованным из базового класса, имеют свои члены: в классе SalariedEmployee описана строковая переменная SocialSecurityNumber, а в класс ContractEmployee включено описание члена FederalTaxId.
Этот небольшой пример показывает, как наследование функциональных возможностей базовых классов позволяет создать повторно используемый код. Кроме того, вы можете расширить эти возможности, добавив собственные переменные и методы.

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