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

         

в этой главе представляют концепции



ПРИМЕЧАНИЕ

Фрагменты кода в этой главе представляют концепции объектно-ориентированного программирования. Помните: хотя я привожу много примеров кода на С#, сами концепции универсальны для ООП и не присущи какому-либо языку программирования. В этой главе будут также представлены для сравнения примеры на С, не являющемся объектно-ориентированным языком.

Допустим, вы пишете приложение для расчета зарплаты служащей вашей фирмы по имени Эми (Amy). Код на С, представляющий данные о служащем, будет выглядеть примерно так:

Struct EMPLOYEE {

char szFirstName[25];

char szLastName[25];

int iAge; double dPayRate;



};

Вот код для расчета зарплаты Эми Андерсон, в котором используется структура EMPLOYEE:

void main()
{

double dTotalPay;

struct EMPLOYEE* pEmp;

pEmp = (struct EMPLOYEE*)malloc(sizeof(struct EMPLOYEE));

if (pEmp) {

pEmp->dPayRate = 100;

strcpy(pEmp->szFirstName, "Эми"); strcpy(pEmp->szLastName, "Андерсон"); pEmp->iAge = 28;

dTotalPay = pEmp->dPayRate * 40; printf("Bce выплаты Xs Xs составляют X0.2f",

pEmp->szFirstName, pEmp->szLastName, dTotalPay); >

free(pEmp);

}

Код этого примера основан на данных, содержащихся в структуре, и на некотором внешнем (по отношению к структуре) коде, обрабатывающем эту структуру. И что же здесь не так? Основной недостаток — в отсутствии абстрагирования: при работе со структурой EMPLOYEE необходимо знать чересчур много о данных, описывающих служащего. Почему это плохо? Допустим, спустя какое-то время вам потребуется определить "чистую" зарплату Эми (после удержания всех налогов). Тогда пришлось бы не только изменить всю клиентскую часть кода, работающую со структурой 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 double CalculatePay(int hoursWorked)

{

// Здесь вычисляется зарплата.
return (payRate * (double)hoursWorked);
}
 }

class EmployeeApp {

public static void MainQ

{

Employee emp = new Employee ("Эми", "Андерсон", 28, 100); Console.WriteLine("\n3apnflaTa Эми составляет $" +

emp.CalculatePay(40)); } 
}

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

Сделаю одно замечание. В клиентской части кода на языке С можно создать функцию доступа к структуре EMPLOYEE. Однако ее придется создавать отдельно от структуры, которую она обрабатывает, и мы окажемся перед той же проблемой. А вот в объектно-ориентированном языке вроде С# данные объекта и методы их обработки (интерфейс объекта) всегда будут вместе.

Помните: модифицировать переменные объекта следует только методами этого же объекта. Как видно из нашего примера, все переменные-члены в Employee объявлены с модификатором доступа protected, a метод CalculatePay — с модификатором public. Модификаторы доступа применяются для задания уровня доступа, который получают производные классы к членам исходного класса. Модификатор protected указывает, что производный класс получит доступ к члену, а клиентский код — нет. Модификатор public делает член доступным и для производных классов, и для клиентского кода. Подробнее на модификаторах доступа я остановлюсь в главе 5, пока же запомните, что модификаторы позволяют защитить ключевые члены класса от нежелательного использования.

 

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