Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

информатика теория

.pdf
Скачиваний:
28
Добавлен:
03.06.2015
Размер:
827.15 Кб
Скачать

Основные определения:

 

-

( П) парадигма программирования, в которой

основнымиконцепциями являются понятия объектов и классов.

А с

ц я

 

Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция — это набор всех таких характеристик.[1]

Исуляц я

Инкапсуляция — это свойство системы, позволяющее объединить данные и методы,

работающие с ними, в классе, и скрыть детали реализации от пользователя.[1]

Н сл д

Наследование — это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым, родительским или суперклассом.

Новый класс — потомком, наследником, дочерним или производным классом.[1]

П л ф з

Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.[1] При использовании термина

«полиморфизм» в сообществе ООП подразумевается полиморфизм подтипов; а

использование параметрического полиморфизманазывают обобщённым программированием.

Кл сс

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

Сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса или копирования прототипа (например, после запуска результатов компиляции и связывания исходного кода на выполнение).

П

Прототип — это объект-образец, по образу и подобию которого создаются другие объекты.

Объекты-копии могут сохранять связь с родительским объектом, автоматически наследуя изменения в прототипе; эта особенность определяется в рамках конкретного языка.

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

Эпоха динозавров без классов и объектов

Ладно, это была шутка, предыдущее предложение не было простым к пониманию «с нуля» и вы, уважаемый начинающий чайник, не совсем полный даун. Следите за пальцами, разъясняю сначала пользу от классов и объектов.

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

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

Тип данных: Колесо { переменная резина: Резина; переменная диск: Диск;

}

Тип данных: Автомобиль { переменная число_дверей: Целое_число;

переменная объем_двигателя: Вещественное_число; переменная марка: Строка; переменная модель: Строка; переменная колесо: Колесо;

...

}

Из псевдокода выше можно заметить, что структура может в себя включать как простые поля, так и другие, ранее определённые, структуры, что очень удобно. К тому же создав переменную (или массив переменных) «авто» типа

«Автомобиль» мы получаем все параметры в одном флаконе и можем писать под это дело функционал, которому на вход подается только одно «авто», а не куча разрозненных данных, связь между которыми существует только в головах разработчиков (а к последним компьютер прямого доступа пока не имеет, и слава богу!).

Основная идея классов, объектов и ООП в целом

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

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

Класс: Автомобиль {

...

переменная марка: Строка; переменная модель: Строка;

...

функция заголовокДляПрайсЛиста() { вернуть марка + " " + модель;

}

}

И это уже можно назвать классом, хотя это, по сути, новый тип данных. Получается, класс — это некий шаблон,

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

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

Объектно ориентированное «программирование» в жизни

В умных книжках вас наверняка напугали «интуитивно понятной» фразой «объект — это экземпляр класса». Давайте возьмем что-то менее интуитивное, но более понятное — из жизни.

И так, класс = шаблон. В реальной жизни можно взять в качестве примера чертёж какой-нибудь важной детали. Пусть

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

внужное место и наслаждаться исправно работающим блоком реактора АЭС (если производство не накосячило).

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

Разумеется, с точки зрения низкоуровневого (системного) программирования, создание объектов не является простой задачей. Поэтому во всех языках для этого существуют отдельные операторы. Но во всем остальном, с объектом можно обращаться как с обычной переменной, хоть и с некоторыми ограничениями, которые легко обходятся за счет функциональности, которой этот объект обладает, или за счет возможностей языка (в частности: перегрузка операторов в C++). То есть, сложить, например, два объекта — матрицы

чисел оператором «+», как обычные числа, скорее всего сразу не получится. Но можно в классе написать соответствующий функционал (которым объекты сразу овладеют) и вызвать его.

результат = матрица_один->суммировать(матрица_два);

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

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

Как работает наследование?

Если вы в школе не прогуливали биологию, то к этому моменту у вас уже могли возникнуть смутные ассоциации с классификацией животного и растительного мира

(животных и растительных объектов). Это хороший пример проектирования с использованием ООП. Примитивные хордовые — непонятные головастики с хрящиком, а у нас, потомков — огого, какой позвоночник со спинным мозгом внутри! Некоторые им даже думать умудряются. Еще одно доказательство тому, что бог — действующий программист. Например, возьмем класс «Автомобиль» из вводной статьи и тут же расширим его, написав новый класс «ПодержанныйАвтомобиль»:

Класс: НовыйАвтомобиль {

...

переменная марка: Строка; переменная модель: Строка;

...

функция заголовокДляПрайсЛиста() { вернуть марка + " " + модель;

}

функция цена() {

...тут как-то считается цена с НДС и проч.

}

}

Класс: ПодержанныйАвтомобиль расширяет НовыйАвтомобиль

{

переменная пробег: Целое_число;

функция цена() {

...тут как-то считается старая цена

...и, дополнительно, учитывается пробег

}

}

В данном примере мы создали новый класспотомок «ПодержанныйАвтомобиль». В дополнение к ранее перечисленным возможностям класса-

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

Зачем нужно наследование?

Ни тебе мучений, ни переписываний кусков кода в разных концах проекта, ни поиска непонятных ошибок. Взяли готовое работающее решение и «слегка обработали напильником», не напрягаясь совершенно. Вспомнился анекдот про то, как американцы несколько раз в секретной лаборатории пытались построить по русским чертежам и инструкциям самолёт Су-31, а получался паровоз. Уже почти до расстрелов дело дошло. Пригласили русских. Те заперлись, открывают через неделю дверь и выкатывают распоследнюю модель истребителя. Летчик садится и взлетает. — Как? — падают в обмороки учёные США. — Ну написано же в конце руководства по сборке: «…и слегка обработать напильником.»

Если смешно — посмейтесь пока можете. Потом, когда с помощью нескольких наследований сделаете из паровоза не только самолёт, а ещё подводную лодку, автобус и человекоподобного робота, рефлексов останется только на нервный тик под глазом. Тем, кто до сих пор не сообразил

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

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

15.07.2010 | 10:32

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

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

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

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

Разумеется — прописывается в классе объекта (класс — шаблон для объектов, помните?). На сегодняшний день выработано три основных уровня инкапсуляции (степени сокрытия или уровней доступа, как

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

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

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

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

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

Класс: Автомобиль {

...

приватная переменная марка: Строка; приватная переменная модель: Строка;

...

функция заголовокДляПрайсЛиста() { вернуть марка + " " + модель;

}

}

Класс ДругойАвтомобиль наследует Автомобиль {

...

функция левыйЗаголовок() { вернуть модель + " левый текст"; //ОШИБКА!

}

...

}

переменная авто = cоздать_объект_класса "Автомобиль";

напечатать авто->марка; //ОШИБКА!

напечатать авто->заголовокДляПрайсЛиста();

//А ЭТО ПРАВИЛЬНО, функция не приватна.

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

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

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

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

использования. Причём, в первую очередь, вами же. А ну как в компьютерной игре нужен новый монстр срочно, за день до выпуска продукта, а в программной части атаку не переопределить?

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

Класс: Автомобиль {

...

защищенная переменная марка: Строка; защищенная переменная модель: Строка;

...

функция заголовокДляПрайсЛиста() { вернуть марка + " " + модель;

}

}

переменная авто = cоздать_объект_класса "Автомобиль";

напечатать авто->марка; //ОШИБКА!

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

Класс: Автомобиль {

...

защищенная переменная марка: Строка; защищенная переменная модель: Строка;

...

функция заголовокДляПрайсЛиста() { вернуть марка + " " + модель;

}

}

Класс ДругойАвтомобиль наследует Автомобиль {

...

функция левыйЗаголовок() {

//ЭТО ПРАВИЛЬНО И РАБОТАЕТ!

вернуть модель + марка +" левый текст";

}

...

}

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

выказывая тем самым определённую степень доверия тому несчастному, которого заставят что-то программировать на основе ваших каракулей.