Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции C# Часть1 A5.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
1.07 Mб
Скачать

Инкапсуляция

До сих пор переменные и методы наших классов описывались с модификатором доступа public. Это позволяло использовать их за пределами класса. Например, для увеличения роста человека, на которого ссылается переменная p можно написать оператор:

p.Height++;

Однако в современном объектно-ориентированном программировании действует правило инкапсуляции, согласно которому все переменные класса делаются закрытыми (private), то есть недоступными за пределами класса. Доступ к этим переменным осуществляется через открытый интерфейс – открытые методы класса.

В связи с этим внесем изменения в класс Person:

class Person

{ private string name;

private double height;

private double weight;

public Person(string Name, double Height, double Weight)

{ name=Name; height=Height; weight=Weight; }

public Person( ){ name=”noname”; height=50; weight=4; }

public void PersonAnalyze()

{ if (height-weight>100.0)

Console.WriteLine(name+" полный");

else

Console.WriteLine(name + " худой");

}

}

Отметим два вида изменений:

  • все переменные класса описаны с использованием модификатора доступа private;

  • имена этих переменных начинаются с маленькой буквы. Хотя это и не является строгим правилом языка, однако большинство программистов делают так, чтобы уже по имени переменной определить ее закрытый статус.

Теперь за пределами класса уже нельзя осуществить непосредственное использование переменных. Однако выход есть (и даже несколько). Например, можно создать в классе два открытых метода для доступа к каждой переменной (их еще называют методами-аксессорами или get- и set- методами):

public double GetHeight() {return height; }

public void SetHeight(double newHeight) { height=newHeight; }

Теперь для увеличения роста человека на единицу потребуется два вызова методов:

p.SetHeight(p.GetHeight()+1);

Главный вопрос здесь – зачем нужно такое ограничение? Ведь последняя строка не только «ужасно» выглядит, но и замедляет выполнение программы. Дело в том, что преимущества инкапсуляции намного важнее, чем упомянутые здесь недостатки.

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

Если оператор

p.Height++;

еще может соответствовать реальному процессу (увеличение роста человека), то как можно содержательно трактовать оператор

p.Height--;

или

p.Height=-10;

Таким образом, непосредственное использование переменных не способствует поддержке правил и ограничений предметной области (так называемых бизнес-правил). Эту проблему можно решить несколькими способами.

1. Использование специализированных методов, соответствующих содержательным действиям в предметной области. Например, метод Grow в классе Person может реализовать естественный рост человека на протяжении некоторого периода:

public void Grow(int days) { . . . }

Реализация такого метода может быть достаточно реалистичной, учитывая возраст человека.

2. Реализацией ограничений в методах доступа:

public void SetHeight (double newHeight)

{ if ((newHeight>0)&&( newHeight<230)&& (newHeight>height))

height=newHeight;

}

3. Реализацией методов-свойств. О свойствах подробнее будет рассказано ниже.

Обратим внимание на важные следствия такого подхода. Класс с его методами и переменными становится в достаточной степени черным ящиком. Пользователю класса не известны ни особенности реализации методов класса, ни даже информационная структура класса. Это позволяет разделить программный проект на разные по роли фрагменты, которые часто взаимодействуют по принципу клиент-сервер. Клиент использует класс, зная его открытый интерфейс. Примером клиента является метод Main, использующий встроенные и пользовательские классы для решения конкретной задачи. Сервер – это класс, предоставляющий свои услуги. Разработчик серверного класса может изменять (совершенствовать) детали его устройства и функционирования, пока это не влияет на открытый интерфейс класса.