Фундаментальные принципы объектно-ориентированного программирования на javascript

Доменный регистратор, или Туда и обратно

Из песочницы

В сентябре 2017 года в компании, где я работала, пошли разговоры о том, что планируется создание Доменного регистратора. Как очень молодой специалист (20 лет и начало 3 курса бакалавриата), я быстро распознала в нём проект, который может дать мне проявить себя. И к моему счастью, то ли в меня настолько поверили, то ли проект не посчитали перспективным, но он достался именно мне, почти целиком и полностью. На момент начала работы я предполагала, что материала будет мало даже для бакалаврского диплома. Я никогда так не ошибалась. Всё, начиная от понимания схемы работы системы, до её проектирования и написания, заняло очень много времени. Было переосмыслено много теории по Сетям, паттернам проектирования и вообще о работе.

Философия ООП ¶

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

Но давайте вернёмся к примеру выше и посмотрим, как можно упростить себе жизнь.

Первое, на что нужно обратить внимание, это то, что мы работаем с пользователем как с массивом:

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

Давайте создадим класс пользователя, который на вход принимает данные пользователя и имеет функцию для возврата имени:

Исправим объявление списка:

Теперь для доступа к имени пользователя можно использовать функцию . Мы «спрятали» (инкапсулировали) структуру исходного массива с данными пользователя за функциями класса . Если исходный массив поменяется, то изменения нужно будет внести только в функции класса.

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

Изменим объявление исходных данных:

Теперь можно обращаться к нашим данным так:

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

Шаблон представляет из себя псевдо язык разметки, в котором в теории удобно делать вёрстку:

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

Фабричный метод без размещения в динамической памяти

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

Роль инкапсуляции

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

Т.е. инкапсуляция представляет собой способности языка скрывать излишние детали реализации от пользователя объекта.
Например, предположим, что используется класс по имени DatabaseReader, который
имеет два главных метода: Open() и Close().

Фиктивный класс DatabaseReader инкапсулирует внутренние детали нахождения,
загрузки, манипуляций и закрытия файла данных. Программистам нравится инкапсуляция, поскольку этот принцип ООП упрощает кодирование. Нет необходимости беспокоиться о многочисленных строках кода, которые работают «за кулисами», чтобы
реализовать функционирование класса DatabaseReader. Все, что потребуется — это
создать экземпляр и отправлять ему соответствующие сообщения (например, «открыть файл по имени AutoLot.mdf, расположенный на диске С:»).

С идеей инкапсуляции программной логики тесно связана идея защиты данных.
В идеале данные состояния объекта должны быть специфицированы с использованием ключевого слова private (или, возможно, protected). Таким образом, внешний мир
должен вежливо попросить, если захочет изменить или получить лежащее в основе значение. Это хороший принцип, поскольку общедоступные элементы данных можно легко повредить (даже нечаянно, а не преднамеренно).

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

Код и данные, составляющие вместе класс, называют членами. Данные, определяемые классом, называют полями, или переменными экземпляра. А код, оперирующий
данными, содержится в функциях-членах, самым типичным представителем которых
является метод. В C# метод служит в качестве аналога подпрограммы. (К числу других
функций-членов относятся свойства, события и конструкторы.) Таким образом, методы класса содержат код, воздействующий на поля, определяемые этим классом.

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

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

Класс, Объект

Данные понятия ООП закрепляют целесообразность использования специального вида компонента, описываемого совокупностью некоторых внутренних данных и методов работы с этими данными. Все утверждения группы и транслируются в ООП, для которого термин компонент заменяется понятием класс.

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

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

Понятие «инкапсуляция» можно рассмотреть с двух «сторон».

Первая сторона понятия «инкапсуляция» — это обособленность компонента от других участков кода. Это свойство позволяет программисту для внесения изменений в компонент выполнить операции в участках кода, которые расположены «близко». То есть минимизировать затраты времени программиста, исключая из работы поиск и анализ разрозненных взаимодействующих элементов программы. Эта сторона задается свойствами компонента, следующими из его определения.

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

Наследование

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

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

Существует множество альтернативных способов использовать связку база + реализация. Приведу далее примеры таких способов.

База Реализация Область применения
Публичные методы класса Приватные методы класса Инкапсуляция
Защищенные методы родительского класса Методы класса-наследника Наследование
Интерфейс динамической библиотеки Функционал динамической библиотеки Компонент=динамическая библиотека
Шаблонные (обобщенные) методы и классы (template, generic) Инстанцирование шаблона с указываемыми аргументами Обобщенное программирование
Универсальные методы, принимающие делегаты Специализация методов указанием конкретных процедур обработки Процедуры сортировки или формирования дерева, с указанием метода оценки порядка элементов
Классы, предусматривающие взаимодействие с шаблоном «Посетитель» Формирование «Посетителя» с требуемым функционалом Шаблон проектирования «Посетитель»
Панель управления АЭС Совокупность автоматики и оборудования АЭС Сокрытие сложности системы от оператора АЭС

Полиморфизм

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

ООБД без ООП

Из песочницы

Лично мне не надо объяснять, что такое ООП. Я сам в первую очередь мыслю существительными и только во вторую — глаголами.
Но речь не о том, кто как мыслит; я хочу обсудить ситуацию, когда отказ от привычных механизмов ООП упрощает работу с объектами.
Как, пример, можно вспомнить добрым словом Lotus Notes, где имя формы хранилось внутри документа. Создавая форму LN, мы тем самым описываем новый UI класс, в котором можно добавлять свойства и переопределять методы (Queryopen, Postsave и пр.). При этом новый объект, созданный с помощью этой формы, не связан с ней механизмом наследования. Форма – это свойство объекта, и в LN есть команда «SwitchForm», с помощью которой можно открыть объект с другой формой, естественно, с вызовом других методов. Неопределенные свойства при этом вернут пустую строку.

Определение классов в C++

Класс — это пользовательский тип данных (также как и структуры). Т.е. тип данных, который вы создаёте сами. Для этого вы пишете определение класса. Определение класса состоит из заголовка и тела. В заголовке ставится ключевое слов class, затем имя класса (стандартный идентификатор C++). Тело помещается в фигурные скобки. В C++ классы и структуры почти идентичны. В языке C в структурах можно хранить только данные, но в C++ в них можно добавить действия.

class Tank {
private:
int ammo;

public:
void Attack() {
ammo -= 1;
}
};

В C++ ключевые слова struct и class очень близки и могут использоваться взаимозаменяемо. У них есть только одно отличие (об этом ниже). Вот как можно определить такой же класс с помощью struct:

struct Tank {
private:
int ammo;

public:
void Attack() {
ammo -= 1;
}
};

Отличие только первом ключевом слове. В одном из прошлых уроков мы уже обсуждали структуры. что мы видим новое? Ключевые слова private и public — это спецификаторы доступа. Также мы видим, что внутри класса мы можем вставлять определения функций.

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

Переменные и методы класса

Класс состоит из членов класса (class members). Члены класса могут быть переменными (data members) или методами (function members или methods). Переменные класса могут иметь любой тип данных (включая другие структуры и классы). Методы — это действия, которые может выполнять класс. По сути, это обычные функции.

Все методы класса имеют доступ к переменным класса

Обратите внимание, как мы обращаемся к ammo в методе Attack

Хук ООП не друг или Динамическое автонаследование классов

Нет предела совершенству. Поэтому, какая бы хорошая и многофункциональная CMS не была, но у сторонних разработчиков всегда будет возникать необходимость ее надстроить, допилить, расширить каким-то своим функционалом. И, конечно, любой современный движок должен позволять это делать.
Причем, механизм расширения функционала движка должен позволять «вешать» на него любое число расширений, написанных разными разработчики, которые не знают ни друг о друге, ни о расширениях, которые пишут другие разработчики.
В различных движках это может делаться разными способами. Наиболее распространенный, наверное, это хуки – сторонний разработчик, создающий расширение для движка, регистрирует обработчики хуков, а потом эти обработчики вызываются системой в нужных местах, выполняя код расширения.
Но когда движок написан с использованием ООП и все разложено на классы, то использование хуков – как это чужеродно и «костыльно», и хочется более чистого и более простого ООП-подхода, когда в создаваемом расширении просто расширяется «коробочный» класс с перекрытием родительских методов.
Вот для решения таких задач и был придуман способ, который я назвал «Динамическое автонаследование».

Абстракция

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

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

Иерархические абстракции сложных систем можно применять и к компьютер­ным программам. Благодаря абстракции данные традиционной, ориентирован­ной на процессы, программы можно преобразовать в составляющие ее объекты, а последовательность этапов процесса — в совокупность сообщений, передавае­мых между этими объектами. Таким образом, каждый из этих объектов описывает свое особое поведение. Эти объекты можно считать конкретными сущностями, реагирующими на сообщения, предписывающие им вътолнитьконкретное действие. В этом, собственно, и состоит вся суть ООП.

Принципы ООП лежат как в основе языка Java, так и восприятия мира человеком

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

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

Что такое RivaTuner Statistics Server? Как установить, настроить и пользоваться программой?

Роль полиморфизма

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

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

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

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

История развития

Основа ООП была заложена в начале 1960-х годов. Прорыв в использовании экземпляров и объектов был достигнут в MIT с PDP-1, и первым языком программирования для работы с объектами стал Simula 67. Он был разработан Кристен Найгаард и Оле-Джохан Даль в Норвегии с целью создания симуляторов. Они работали над симуляциями взрыва кораблей и поняли, что могут сгруппировать корабли в различные категории. Каждому типу судна было решено присвоить свой собственный класс, который должен содержать в себе набор уникальных характеристик и данных. Таким образом, Simula не только ввела понятие класса, но и представила рабочую модель.

Термин «объектно-ориентированное программирование» был впервые использован Xerox PARC в языке программирования Smalltalk. Понятие ООП использовалось для обозначения процесса использования объектов в качестве основы для расчетов. Команда разработчиков была вдохновлена проектом Simula 67, но они спроектировали свой язык так, чтобы он был динамичным. В Smalltalk объекты могут быть изменены, созданы или удалены, что отличает его от статических систем, которые обычно используются. Этот язык программирования также был первым, использовавшим концепцию наследования. Именно эта особенность позволила Smalltalk превзойти как Simula 67, так и аналоговые системы программирования.

Simula 67 стала новаторской системой, которая впоследствии стала основой для создания большого количества других языков программирования, в том числе Pascal и Lisp. В 1980-х годах объектно-ориентированное программирование приобрело огромную популярность, и основным фактором в этом стало появление языка С++

Концепция ООП также имела важное значение для разработки графических пользовательских интерфейсов. В качестве одного из самых ярких примеров можно привести структуру Cocoa, существующую в Mac OS X

Общие принципы модели стали применяться во многих современных языках программирования. Некоторые из них — Fortran, BASIC, Pascal. На тот момент многие программы не были разработаны с учетом ООП, что было причиной возникновения некоторых проблем совместимости. “Чистые” объектно-ориентированные языки программирования не обладали многими функциями, необходимыми программистам. Для решения этих проблем ряд исследователей предложили несколько новых языков программирования, созданных на основе принципов ООП с сохранением других, необходимых программистам, функций. Среди наиболее ярких примеров можно выделить Eiffel, Java, .NET. Даже в серьезных веб-разработках используются языки программирования, основанные на принципах ООП — PHP (у нас вы можете пройти курс ООП в PHP), Python, Ruby. По мнению экспертов, в ближайшие несколько десятилетий именно объектно-ориентированный подход будет оставаться основной парадигмой в развитии программирования.

Метаобъектный протокол Common Lisp на примере реализации прототипной объектной системы

Введение

Common Lisp, а точнее, его объектная система, CLOS, предоставляет пользователю языка совершенно замечательный механизм, а именно, метаобъектный протокол.
К сожалению, очень часто этот компонент языка незаслуженно остается без должного внимания, и в данной статье я постараюсь это несколько компенсировать.
Вообще, что такое метаобъектный протокол? Очевидно, это слой объектной системы, который, судя по названию, каким-либо образом оперирует над ней самой, и управляет ей.
Для чего он нужен? На самом деле, в зависимости от языка и объектной системы, список применений может быть практически безграничен. Это как добавление коду декларативности(аннотации в Java и аттрибуты в C#), так и разнообразная генерация кода и классов в рантайме(здесь можно вспомнить разнообразные persistance и ORM фреймворки), так и многое другое.
С моей лично точки зрения, лучше всего метаобъектные протоколы себя зарекомендовали со стороны закрепления паттернов проектирования на уровне объектной системы. Такие паттерны, как, скажем, синглтон, которые в языках без достаточно развитого ООП приходится снова и снова реализовывать методом copy-n-paste, в моем любимом Common Lisp создаются буквально из пары десятков строчек кода и переиспользуются в дальнейшем исключительно указанием метакласса.
Тем не менее, в нижеследующем тексте я хочу сосредоточиться на кое-чем более интересном, а именно — на изменении правил работы самой объектной системы, самих ее основ. Именно добавление возможностей подобного изменения и было ключевой целью разработчиков метаобъектного протокола для Common Lisp.
Итак, дальнейший текст будет посвящен созданию прототипной объектной системы, подобной JavaScript, в Common Lisp, с использованием метаобъектного протокола и интеграцией ее в CLOS. Полный код проекта доступен на github.

Развитие программного проекта

Что такое проект без необходимости развития? Такие проекты изредка встречаются и в основном характеризуются быстрой сдельной оплатой без возникновения последующих обязательств со стороны программиста, например:

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

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

Во всех остальных ситуациях программист, минимизируя свой труд, должен развивать структурно-сложный проект, то есть:

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

Если поискать аналогии развитию программного проекта, то можно вспомнить эволюцию биологического вида.

Труд программиста не легок, но у программиста есть «помощник». Этот помощник спрятан где-то глубоко в устройстве нашего мира, в котором есть две особенности:

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

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

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

Здесь попробую выписать примеры использования абстрагирования из разных областей.

Абстракция Алгоритмы Область применения
Натуральные числа Алгоритмы количественных расчетов Задачи учёта хозяйственных ценностей
Масса-характеристика материального тела Алгоритмы-операций сравнения количества вещества Задачи сравнения ценности товара, не поддающегося счету
Интерфейс с операциями для коллекции элементов: полный обход, сравнение и обмен позиций Алгоритмы сортировки коллекции Программирование
Интерфейс одинаковых операций для «концевого узла» и «узла ветвления» в дереве Алгоритмы на основе шаблона проектирования «Компоновщик» Разработка сложного программного проекта
Ключевое понятие «Работник» Формулировки в разделе «Трудовой договор» Трудовой кодекс

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

Любая функция в программе представляет собой метод для объекта некоторого класса.
Класс должен формироваться в программе естественным образом, как только в ней возникает необходимость описания новых объектов программирования. Каждый новый шаг в разработке алгоритма должен представлять собой разработку нового класса на основе уже существующих.
Вся программа в таком виде представляет собой объект некоторого класса с единственным методом run (выполнить).
Программирование «от класса к классу» включает в себя ряд новых понятий. Основными понятиями ООП являются

  • инкапсуляция;
  • наследование;
  • полиморфизм.

Инкапсуляция данных (от «капсула») – это механизм, который объединяет данные и код, манипулирующий с этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В ООП код и данные могут быть объединены вместе (в так называемый «черный ящик») при создании объекта.
Внутри объекта коды и данные могут быть закрытыми или открытыми.
Закрытые коды или данные доступны только для других частей того же самого объекта и, соответственно, недоступны для тех частей программы, которые существуют вне объекта.
Открытые коды и данные, напротив, доступны для всех частей программы, в том числе и для других частей того же самого объекта.Наследование. Новый, или производный класс может быть определен на основе уже имеющегося, или базового класса.
При этом новый класс сохраняет все свойства старого: данные объекта базового класса включаются в данные объекта производного, а методы базового класса могут быть вызваны для объекта производного класса, причем они будут выполняться над данными включенного в него объекта базового класса.
Иначе говоря, новый класс наследует как данные старого класса, так и методы их обработки.
Если объект наследует свои свойства от одного родителя, то говорят об одиночном наследовании. Если объект наследует данные и методы от нескольких базовых классов, то говорят о множественном наследовании.
Пример наследования – определение структуры, отдельный член которой является ранее определенной структурой.Полиморфизм – это свойство, которое позволяет один и тот же идентификатор (одно и то же имя) использовать для решения двух и более схожих, но технически разных задач.
Целью полиморфизма, применительно к ООП, является использование одного имени для задания действий, общих для ряда классов объектов. Такой полиморфизм основывается на возможности включения в данные объекта также и информации о методах их обработки (в виде указателей на функции).
Будучи доступным в некоторой точке программы, объект , даже при отсутствии полной информации о его типе, всегда может корректно вызвать свойственные ему методы.Полиморфная функция – это семейство функций с одним и тем же именем, но выполняющие различные действия в зависимости от условий вызова.
Например, нахождение абсолютной величины в языке Си требует трех разных функций с разными именами:

123

int abs(int);long int labs(long int);double fabs(double);

Язык C++

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector