Принципы (свойства) ООП: инкапсуляция для чайников (public, protected, private)

Инкапсуляция (по-русски: «сокрытие») — это свойство объектов скрывать некоторые свои данные и способы их обработки (методы) от окружающей его цифровой среды и, в частности, от кривых ручонок малоопытных программистов, оставляя «снаружи» только необходимые и/или требуемые свойства и функциональные возможности.

С точки зрения стороннего программиста объект выглядит этаким «чёрным ящиком», у которого есть входы и выходы. Подавая на входы данные и дёргая за торчащие рычажки (функциональные методы) можно получить какой-то результат на выходе.

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

Как это достигается?

Разумеется — прописывается в классе объекта (класс — шаблон для объектов, помните?). На сегодняшний день выработано три основных уровня инкапсуляции (степени сокрытия или уровней доступа, как хотите): public, protected и private. Обычно эта «святая троица» имеется в каждом языке программирования, в котором реализована объектно-ориентированная концепция.

Существует понятие «область видимости» чего-либо в программе (функции, переменной, свойств и методов класса). Область видимости определяет, можете-ли вы обратиться с этого места программы к какой-либо конструкции, или нет. Основное назначение этого понятия — предотвращение путаницы с переменными, минимизация ошибок путём предупреждения разработчика о возможных коллизиях и несуразицах заранее, экономия памяти с помощью автоматического освобождения места, которое занимали различные программные объекты, выпавшие из области видимости «навсегда» (например: локальные переменные внутри функций). Данные модификаторы призваны регулировать видимость свойств и методов внутри и снаружи класса и объектов класса.

Модификатор «private»: никому не дам

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

Класс: Автомобиль {
  ...
  приватная переменная марка: Строка;
  приватная переменная модель: Строка;
  ...
  функция заголовокДляПрайсЛиста() {
    вернуть марка + " " + модель;
  }
}
 
Класс ДругойАвтомобиль наследует Автомобиль {
  ...
  функция левыйЗаголовок() {
    вернуть модель + " левый текст"; //ОШИБКА!
  }
  ...
}
 
переменная авто = cоздать_объект_класса "Автомобиль";
 
напечатать авто->марка; //ОШИБКА!
 
напечатать авто->заголовокДляПрайсЛиста();
//А ЭТО ПРАВИЛЬНО, функция не приватна.

В вышеприведенном фрагменте идиотского псевдоязыка («приватная» соответствует «private») видно, что некто, опасаясь некорректного изменения свойств «марка» и «модель», спрятал их. Все, что засунуто под «private» видно только внутри того класса, в котором описано (здесь — в классе «Автомобиль»). Ни в его наследниках, ни в объектах этого и наследующих классов приватные свойства и методы доступны не будут. При попытках подобного обращения, как в классе «ДругойАвтомобиль» и, тем более, из объектов (вторая ошибка) программисту будет выдаваться пугающее сообщение об ошибке насчёт отсутствия данных свойств и методов, и программа будет отказываться запускаться.

В данном случае «private», переводится с английского, не как «рядовой» (Райан, которого спасти надо), а как «частный». Также как и во фразе «private property» — частная собственность. Кстати (!) «property» в программировании и переводится как «свойство». Так что если видите в какой-либо документации что-то типа «private property elementCount...», то уже даже напрямую всё понятно: это свойство — частная собственность класса, и не надо на него посягать. Хотя, в основном, компьютерной братией употребляется слово «приватный».

Модификатор «protected»: дам только ему

Но впадать в параноидальные страхи и «приватить» все подряд тоже нехорошо. Это резко обрубит возможные пути по модификации и расширению ваших классов при наследовании и, соответственно, более широкого их использования. Причём, в первую очередь, вами же. А ну как в компьютерной игре нужен новый монстр срочно, за день до выпуска продукта, а в программной части атаку не переопределить?

Поэтому и существует компромиссный вариант: protected — защищенный (метод или свойство). Как и приватные, защищенные конструкции не видны «снаружи» объекта.

Класс: Автомобиль {
  ...
  защищенная переменная марка: Строка;
  защищенная переменная модель: Строка;
  ...
  функция заголовокДляПрайсЛиста() {
    вернуть марка + " " + модель;
  }
}
 
переменная авто = cоздать_объект_класса "Автомобиль";
 
напечатать авто->марка; //ОШИБКА!

Отличие проявляется, если мы решим расширить класс и как-то его модифицировать. Внутри класса protected-конструкции видны, и мы можем их использовать.

Класс: Автомобиль {
  ...
  защищенная переменная марка: Строка;
  защищенная переменная модель: Строка;
  ...
  функция заголовокДляПрайсЛиста() {
    вернуть марка + " " + модель;
  }
}
 
Класс ДругойАвтомобиль наследует Автомобиль {
  ...
  функция левыйЗаголовок() {
    //ЭТО ПРАВИЛЬНО И РАБОТАЕТ!
    вернуть модель + марка +" левый текст";
  }
  ...
}

Другими словами, объявляя что-либо protected вы убиваете сразу несколько зайцев, несмотря на то, что собирались вообще на рыбалку. Сначала вы прячете «ошибкоопасную» конструкцию от несанкционированного использования извне. Но, затем, получается, разрешаете её использовать при наследовании данного класса внутри наследника, выказывая тем самым определённую степень доверия тому несчастному, которого заставят что-то программировать на основе ваших каракулей.

В результате, вы сами, или кто-то ещё, может расширять и модифицировать классы с использованием уже готовых их частей. Естественно, если вы используете что-то с модификатором protected (чаще всего это вызов или переопределение методов родительского класса), то вы или сами это всё наваяли, или «расписываетесь» в том, что вашей квалификации и степени разумности хватает для подобных действий. Напортачили? Сами виноваты.

Модификатор «public»: кому бы дать?

Те, кто слышал о существовании английского языка уже догадались, что «public» означает «публичный», «общедоступный». Хорошо, пусть будет публичный дом, если кому-то так хочется (да-да, валите всё на двусмысленные заголовки). Свойства и методы объекта, объявленные в классе публичными, доступны «снаружи» объекта и являются как раз теми самыми входами, выходами и управляющими рычажками, с помощью которых разработчик данного класса позволил другим программистам управлять поведением объектов этого класса.

Обратите внимание на предыдущий абзац ещё раз. Да не на публичный дом! А на взаимоотношения «класс-объект», выделенные курсивом. Если увидите, что из чего проистекает, ваша речь по этому вопросу станет гораздо грамотнее и вы перестанете раздражать общественность сентенциями вроде «выложил свой объект в сеть» и «создал в программе новый класс».

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

Класс: Автомобиль {
  ...
  публичная переменная марка: Строка;
  публичная переменная модель: Строка;
  ...
  публичная функция заголовокДляПрайсЛиста() {
    вернуть марка + " " + модель;
  }
}
 
Класс ДругойАвтомобиль наследует Автомобиль {
  ...
  публичная функция левыйЗаголовок() {
    вернуть модель + марка +" левый текст";
  }
  ...
}
 
переменная авто = cоздать_объект_класса "Автомобиль";
переменная авто2 = cоздать_объект_класса "ДругойАвтомобиль";
 
напечатать авто->заголовокДляПрайсЛиста();
напечатать авто2->марка;

Обязательно изучайте конкретные реализации

При освоении нового для вас языка программирования, обязательно сразу лезьте читать про особенности реализации ООП в целом и как сделано управление видимостью private-protected-public. Везде свои особенности. Например, в Java сами классы могут объединяться в пакеты классов и быть приватными или защищенными внутри пакетов. В итоге получаем дополнительный уровень доступа, дающий, с одной стороны, более широкие возможности по структуризации программы, а с другой стороны — дополнительные оттенки проектирования, которые надо учитывать.

Важно внимательно уяснить себе все возможности и, главное, понять для чего они нужны (чему, кстати, очень помогает изучение исходников от профессиональных программистов). Начнёте думать в том же ключе, как и создатели языка, или какого-то пакета — считайте уже сами выбрались из серой массы начинающих.

15.07.2010 | 15:37




 
Добавить комментарий


Защитный код
Обновить