Императивное программирование
Первыми императивными языками были машинные коды – «родной язык» программирования для компьютера. В этих языках инструкции были крайне просты, что снижало нагрузку на компьютеры, однако затрудняло написание крупных программ. В 1954 появился первый язык программирования –Fortran, а затем Algol, Pascal и C.
В отличие от функционального программирования (относящегося к декларативной парадигме), при императивном подходе интенсивно используется присваивание, что увеличивает сложность моделей вычислений и делает императивные программы подверженными специфическим ошибкам, не встречающимся при функциональном программировании
То есть одной из характерных черт императивного программирования является наличие переменных с операцией «разрушающего присвоения». Значит, имеется переменная А, которая содержит значение Х. На очередном шаге алгоритм предписывает присвоить переменной А значение Y. То значение, которое было у переменной А, будет «навсегда забыто». На практике это означает «переход между состояниями под управлением функции переходов».
Примерами могут служить такие языки, как FORTRAN, BASIC, ALGOL, PL/1, PASCAL, C, ADA.
Покажем на бытовом примере императивную программу:
Procedure Вскипятить_чайник
begin
Зажечь плиту;
Взять чайник;
Налить в чайник воды;
Поставить на плиту;
Подождать 5 минут;
end
begin
if Чайник не пуст then
Вылить из чайника воду;
Вскипятить_чайник;
end.
Императивное программирование наиболее пригодно для реализации небольших подзадач, где очень важна скорость исполнения на современных компьютерах. Кроме этого, работа с внешними устройствами, как правило, описывается в терминах последовательного исполнения операций («открыть кран, набрать воды»), что делает такие задачи идеальными кандидатами на императивную реализацию.
Декларативное программирование
В 60-х годах возникает новый подход к программированию, который до сих пор успешно конкурирует с императивным, а именно, декларативный подход.
Декларативное программирование подразумевает использование данных, а не написание кода для того, чтобы заставить приложение или компонент выполнить что-либо.
На начальном этапе развития декларативным языкам программирования было сложно конкурировать с императивными в силу объективных трудностей эффективной реализации трансляторов. Программы работали медленнее, однако они могли решать более абстрактные задачи с меньшими трудозатратами.
В основе декларативных языков лежит формализованная человеческая логика. Человек лишь описывает решаемую задачу, а поиском решения занимается императивная система программирования. То есть декларативное описание задачи более наглядно и легче формулируется, так как мы чаще знаем, чего хотим, но не знаем как сделать.
В итоге получаем значительно большую скорость разработки приложений, значительно меньший размер исходного кода, легкость записи знаний на декларативных языках, более понятные, по сравнению с императивными языками, программы.
Известна классификация языков программирования по их близости либо к машинному языку, либо к естественному человеческому языку. Те, что ближе к компьютеру, относят к языкам низкого уровня, а те, что ближе к человеку, называют языками высокого уровня.
В этом смысле декларативные языки можно назвать языками сверхвысокого или наивысшего уровня, поскольку они очень близки к человеческому языку и человеческому мышлению.
Декларативные программы не используют понятия состояния и, в частности, не содержат переменных и операторов присваивания.
Разновидностями декларативного программирования являются функциональное и логическое программирование, хотя в действительности программы на таких языках нередко содержат алгоритмические составляющие, так что правильнее говорить об ограниченных формах декларативного программирования.
Примером декларативного языка служит HTML, описывающий содержание страницы, а не способ её отображения на экране. Популярный сборщик пакетов Maven описывает лишь зависимости между пакетами, а не последовательность их установки. Язык запросов SQL описывает, что мы хотим достать из базы данных, как именно решает сервер.
Другие характерные примеры декларативных языков программирования: Haskell, Prolog.
С математической точки зрения, декларативная программа представляет собой формальную теорию, а её выполнение является автоматическим доказательством этой теории.
Билет 7
Функциональное и процедурное программирование
Прежде чем говорить непосредственно о данных понятиях, расскажем определение парадигмы программирования.
Парадигма программирования – совокупность идей и понятий, определяющая стиль написания программы.
Одним из путей развития декларативного стиля программирования стал функциональный подход, возникший после создания языка LISP
Функциональное программирование — парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании последних (в отличие от функций как подпрограмм в процедурном программировании).
Противопоставляется парадигме императивного программирования, которая описывает процесс вычислений как последовательное изменение состояний (в значении, подобном таковому в теории автоматов). При необходимости, в функциональном программировании вся совокупность последовательных состояний вычислительного процесса представляется явным образом, например, как список.
Функциональное программирование предполагает обходиться вычислением результатов функций от исходных данных и результатов других функций, и не предполагает явного хранения состояния программы. Соответственно, не предполагает оно и изменяемость этого состояния (в отличие от императивного, где одной из базовых концепций является переменная, хранящая своё значение и позволяющая менять его по мере выполнения алгоритма).
Сильные стороны:
1) Повышение надежности кода (за счёт чёткой структуризации и отсутствия необходимости отслеживания побочных эффектов).
2) Удобство организации модульного тестирования (возможность протестировать каждую функцию в программе, просто вычислив её от различных наборов значений аргументов).
3) Возможности оптимизации при компиляции.
4) Возможности параллелизма (всегда допустимо параллельное вычисление двух различных параметров. Порядок их вычисления не может оказать влияния на результат вызова).
Недостатки:
Недостатки функционального программирования вытекают из тех же самых его особенностей.
1) Отсутствие присваиваний и замена их на порождение новых данных приводят к необходимости постоянного выделения и автоматического освобождения памяти, поэтому в системе исполнения функциональной программы обязательным компонентом становится высокоэффективный сборщик мусора.
2) Нестрогая модель вычислений приводит к непредсказуемому порядку вызова функций, что создает проблемы при вводе-выводе, где порядок выполнения операций важен.
Для преодоления недостатков функциональных программ уже первые языки функционального программирования включали не только чисто функциональные средства, но и механизмы императивного программирования (присваивание, цикл, «неявный PROGN» были уже в LISPе). Использование таких средств позволяет решить некоторые практические проблемы, но означает отход от идей (и преимуществ) функционального программирования и написание императивных программ на функциональных языках. В чистых функциональных языках эти проблемы решаются другими средствами, например, в языке Haskell ввод-вывод реализован при помощи монад — нетривиальной концепции, позаимствованной из теории категорий.
Примерами языков функционального программирования могут являться Python, Lisp, Haskell, Hope, ML (Meta Language — семейство строгих языков функционального программирования.)
Таким образом, при создании программ на функциональных языках программист сосредотачивается на области исследований (предметной области) и в меньшей степени заботится о рутинных операциях (обеспечении правильного с точки зрения компьютера представления данных, "сборке мусора" и т.д.).
Процедурное программирование — программирование на императивном языке, при котором последовательно выполняемые операторы можно собрать в подпрограммы, то есть более крупные целостные единицы кода, с помощью механизмов самого языка.
То есть процедурное программирование представляет собой последовательность команд, определяющих алгоритм решения задачи.
Основная идея процедурного программирования - использование памяти для хранения данных.
Основная команда - присвоение, с помощью которой определяется и меняется память компьютера. Программа производит преобразование содержимого памяти, изменяя его от исходного состояния к результирующему.
Рассмотрим примеры, более подробно описывающие процедурный язык в разные промежутки времени. Различают следующие языки процедурного программирования:
1) Язык Фортран создан в начале 50-х годов 20-го века для программирования научно-технических задач; Первая публикация о нем появилась в 1954 г. Объектами языка являются целые и вещественные числа и числовые переменные. Выражения в нем формируются с помощью четырех арифметических действий: возведения в степень, логических операций И, ИЛИ, НЕ, операций отношения и круглых скобок. Основные операторы Фортрана — ввод, вывод, присваивание, условный и безусловный переход, цикл, вызов подпрограмм.
2) Кобол – создан в конце 60-х годов 20-го века для решения задач обработки больших объемов данных, хранящихся на различных носителях данных; Широко используется для решения учетно-экономических и управленческих задач. Программа на Коболе имеет вид ряда предложений на английском языке и напоминает обычный текст. Группы последовательно записанных операторов объединяются в предложения, предложения — в параграфы, параграфы — в секции. Программист присваивает параграфам и секциям имена (метки), что облегчает непосредственное обращение к нужному участку программы.
3) Алгол (1960 год) – это многоцелевой расширенный язык программирования. В нем впервые введены понятия “блочная структура программы” и “динамическое распределение памяти”;
4) Язык Паскаль (PASCAL) (1968-1971гг)- язык процедурного программирования наиболее популярный для ПК, который и в настоящее время успешно применяется. В основу языка Pascal положен подход от общей задачи к частным (более простым и меньшим по объему). К основным принципам, которыми обладает Паскаль, можно отнести: а) Структурное программирование, которое основано на использовании подпрограмм и независимых структур данных; б) Программирование “сверху-вниз”, когда задача делится на простые, самостоятельно решаемые задачи. Затем выстраивается решение исходной задачи полностью сверху вниз.
5) К языкам процедурного программирования можно отнести язык АДА (1979 г) Язык назван в честь первой программистки Ады Лавлейс- дочери Байрона. Его отличает модульность конструкций.
6) Язык СИ (начало 70-х годов). Одной из особенностей языка СИ является то, что различия между выражениями и операторами сглаживаются, что приближает его к функциональным языкам программирования. Кроме того, в языке СИ отсутствует понятие процедуры, а использование подпрограмм основано на понятии функции, которая может сочетать в себе возможности процедуры.
Теоретической моделью процедурного программирования служит алгоритмическая система под названием Машина Тьюринга.
Программа на процедурном языке программирования состоит из последовательности операторов (инструкций), задающих процедуру решения задачи. Выполнение программы сводится к последовательному выполнению операторов с целью преобразования исходного состояния памяти, то есть значений исходных данных, в заключительное, то есть в результаты. Таким образом, с точки зрения программиста имеются программа и память, причем первая последовательно обновляет содержимое последней.
Билет 8
Объектно-ориентированное программирование
Важным шагом на пути к совершенствованию языков программирования стало появление объектно-ориентированного подхода к программированию (ООП) и соответствующего класса языков.
Объектно-ориентированное программирование — это парадигма программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Для лучшего понимания ООП необходимо знать следующие определения:
Класс – это тип, описывающий устройство объектов. Понятие «класс» подразумевает некоторое поведение и способ представления.
Класс можно сравнить с чертежом, согласно которому создаются объекты. Обычно классы разрабатывают таким образом, чтобы их объекты соответствовали объектам предметной области.
Классявляется описываемой на языке терминологии (пространства имён) исходного кода моделью ещё не существующей сущности – объекта.
Объект – сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса (например, после запуска результатов компиляции исходного кода на выполнение).
Понятие «объект» подразумевает нечто, что обладает определённым поведением и способом представления. Говорят, что объект — это экземпляр класса.
Прототип – это объект-образец, по образу и подобию которого создаются другие объекты.
Поля (или свойства, в рамках C++ это можно считать синонимом) описывают то, какие данные смогут хранить экземпляры класса (т.е. объекты). Конкретные значения сохраняются уже внутри объектов. Поля объявляются в теле класса.
Методы класса — это функции, которые смогут применяться к экземплярам класса. Грубо говоря, метод — это функция, объявленная внутри класса и предназначенная для работы с его объектами.
Несомненным преимуществом данного подхода является концептуальная близость к предметной области произвольной структуры и назначения. Механизм наследования атрибутов и методов позволяет строить производные понятия на основе базовых и таким образом создавать модель сколь угодно сложной предметной области с заданными свойствами.
Еще одним теоретически интересным и практически важным свойством объектно- ориентированного подхода является поддержка механизма обработки событий, которые изменяют атрибуты объектов и моделируют их взаимодействие в предметной области.
ООП основано на «трех китах» - трех важнейших принципах, придающих объектам новые свойства. Этими принципами являются инкапсуляция, наследование и полиморфизм.
1) Наследование – свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым, родительским или суперклассом. Новый класс — потомком, наследником, дочерним или производным классом.
2) Полиморфизм – свойство, позволяющее присваивать действию одно и то же имя, которое затем совместно используется вниз и вверх по иерархии объектов, причем каждый объект иерархии выполняет это действие способом, именно ему подходящим.
3) Инкапсуляция- свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе.
Суть инкапсуляции: Переменные состояния объекта скрыты от внешнего мира. Изменение состояния объекта (его переменных) возможно ТОЛЬКО с помощью его методов (операций). Почему это так важно? Этот принцип позволяет защитить переменные состояния объекта от неправильного их использования.
Применение этого метода ведет к снижению эффективности доступа к элементам объекта. Это обусловлено необходимостью вызова методов для изменения внутренних элементов (переменных) объекта. Однако, при современном уровне развития вычислительной техники, эти потери в эффективности не играют существенной роли.
Пожалуй, наиболее известным примером объектно-ориентированного языка программирования является язык C++, развившийся из императивного языка С.
Наиболее востребованными объектно-ориентированными языками программирования, помимо C++, являются на сегодняшний момент Java и C#. Другие примеры объектно-ориентированных языков программирования: Visual Basic, Eiffel, Oberon.
Билет 9
Методы типового проектирования. Унифицированный язык визуального моделирования (UML – Unified Modeling Language)
Типовое проектирование информационных систем предполагает создание системы из готовых типовых элементов.
Основополагающим требованием для применения методов типового проектирования является возможность декомпозиции проектируемой ИС на множество составляющих компонентов (подсистем, комплексов задач, программных модулей и т.д.). Для реализации выделенных компонентов выбираются имеющиеся на рынке типовые проектные решения, которые настраиваются на особенности конкретного предприятия.
Для реализации типового проектирования используются два подхода:
1) параметрически-ориентированное
2) модельно-ориентированное проектирование.
Параметрически-ориентированное проектирование включает следующие этапы: определение критериев оценки пригодности пакетов прикладных программ (ППП) для решения поставленных задач, анализ и оценка доступных ППП по сформулированным критериям, выбор и закупка наибо- лее подходящего пакета, настройка параметров (доработка) закупленного ППП.
Модельно-ориентированное проектирование заключается в адаптации состава и характеристик типовой ИС в соответствии с моделью объекта автоматизации. Технология проектирования в этом случае должна обеспечивать единые средства для работы как с моделью типовой ИС, так и с моделью конкретного предприятия.
Модельно- ориентированное проектирование ИС предполагает, прежде всего, построение модели объекта автоматизации с использованием специального программного инструментария (например, SAP Business Engineering Workbench (BEW), BAAN Enterprise Modeler)
UML (Unified Modeling Language унифицированный язык моделирования) – язык графического описания для объектного моделирования в области разработки программного обеспечения.
UML является языком широкого профиля, это – открытый стандарт, использующий графические обозначения для создания абстрактной модели системы, называемой UML-моделью.
UML был создан для определения, визуализации, проектирования и документирования, в основном, программных систем. UML не является языком программирования, но на основании UML-моделей возможна генерация кода. UML позволяет также разработчикам программного обеспечения достигнуть соглашения в графических обозначениях для представления общих понятий (таких как класс, компонент, обобщение, агрегация и поведение) и больше сконцентрироваться на проектировании и архитектуре.
В 1994 году Гради Буч и Джеймс Рамбо, работавшие в компании Rational Software, объединили свои усилия для создания нового языка объектно-ориентированного моделирования. За основу языка ими были взяты методы моделирования Object-Modeling Technique и Booch. OMT был ориентирован на анализ, а Booch — на проектирование программных систем. В октябре 1995 года была выпущена предварительная версия 0.8 унифицированного метода (Unified Method). Осенью 1995 года к компании Rational присоединился Ивар Якобсон, автор метода Object-Oriented Software Engineering — OOSE. Группа разработчиков в OMG, в которую также входили Буч, Рамбо и Якобсон, выпустила спецификации UML версий 0.9 и 0.91 в июне и октябре 1996 года.
Сущности UML
В UML используются следующие виды диаграмм:
Структурные диаграммы:
· Диаграмма классов
· Диаграмма компонентов
· Диаграмма композитной/составной структуры
· Диаграмма кооперации
· Диаграмма развёртывания
· Диаграмма объектов
· Диаграмма пакетов
· Диаграмма профилей
Диаграммы поведения:
· Диаграмма деятельности
· Диаграмма состояний
· Диаграмма вариантов использования
Диаграммы взаимодействия:
· Диаграмма коммуникации
· Диаграмма обзора взаимодействия
· Диаграмма последовательности
· Диаграмма синхронизации
Рассмотрим некоторые диаграммы более подробно.
Диаграмма классов
Диаграмма классов (Class diagram) — статическая структурная диаграмма, описывающая структуру системы, демонстрирующая классы системы, их атрибуты, методы и зависимости между классами.
· Является центральным звеном ООП.
· Содержит информацию об объектах системы и статических связях между объектами
· Отражает декларативные знания о предметной области
· Оперирует понятиями класса, объекта, отношения, пакета.
Диаграмма компонентов (Component diagram) — статическая структурная диаграмма, показывает разбиение программной системы на структурные компоненты и связи (зависимости) между компонентами. В качестве физических компонентов могут выступать файлы, библиотеки, модули, исполняемые файлы, пакеты и т. п.
Диаграмма развёртывания (Deployment diagram, диаграмма размещения) — служит для моделирования работающих узлов иартефактов, развёрнутых на них. В UML 2 на узлах разворачиваются артефакты, в то время как в UML 1 на узлах разворачивались компоненты. Между артефактом и логическим элементом (компонентом), который он реализует, устанавливается зависимость манифестации.
Диаграмма объектов (Object diagram) — демонстрирует полный или частичный снимок моделируемой системы в заданный момент времени. На диаграмме объектов отображаются экземпляры классов (объекты) системы с указанием текущих значений их атрибутов и связей между объектами.
Преимущества UML
· UML объектно-ориентирован, в результате чего методы описания результатов анализа и проектирования семантически близки к методам программирования на современных объектно-ориентированных языках
· UML позволяет описать систему практически со всех возможных точек зрения и разные аспекты поведения системы;
· Диаграммы UML сравнительно просты для чтения после достаточно быстрого ознакомления с его синтаксисом;
· UML расширяет и позволяет вводить собственные текстовые и графические стереотипы что способствует его применению не только в сфере программной инженерии;
· UML получил широкое распространение и динамично развивается.
Билет 10
Аспекты ОО-разработки программного обеспечения. Абстрактные типы данных.
Первая и главная идея, лежащая в основе объектно-ориентированного подхода такова: программная система представляется в виде множества самостоятельных сущностей (объектов), взаимодействующих друг с другом. Каждая сущность сама отвечает за хранение информации, необходимой для ее жизни, и, кроме того, она имеет (реализует) свое собственное поведение.
Объектно-ориентированная разработка программного обеспечения связана с применением объектно-ориентированных методологий (технологий). Обычно эти объектно-ориентированные методологии поддерживаются инструментальными программными средствами.
Объектно-ориентированная разработка программ помогает справиться с такими сложными проблемами, как:
— уменьшение сложности программного обеспечения;
— повышение надежности программного обеспечения;
— обеспечение возможности модификации отдельных компонентов программного обеспечения без изменения остальных его компонентов;
— обеспечение возможности повторного использования отдельных компонентов программного обеспечения.
В настоящее время существует несколько технологий объектно-ориентированной разработки прикладных программных систем, в основе которых лежит построение и интерпретация на компьютере моделей этих систем. Одна из таких технологий - OMT (Object Modeling Techniques). Эта технология оказала большое влияние на других разработчиков объектно-ориентированных технологий, а книга, в которой она описана, является одной из наиболее часто цитируемых книг по данному направлению. Более того, система обозначений (графический язык) для описания моделей, предложенная в этой книге, широко применяется в других технологиях и в статьях по объектно-ориентированной разработке программных систем.
Абстрактный тип данных (АТД) — это тип данных, который предоставляет для работы с элементами этого типа определённый набор функций, а также возможность создавать элементы этого типа при помощи специальных функций.
Вся внутренняя структура такого типа спрятана от разработчика программного обеспечения — в этом и заключается суть абстракции. Абстрактный тип данных определяет набор функций, независимых от конкретной реализации типа, для оперирования его значениями. Конкретные реализации АТД называются структурами данных.
В большинстве современных императивных языков основной концепцией, используемой для описания абстракций в программном коде, является объектно-ориентированный подход. Объектно-ориентированное программирование (ООП) также, как и подход к программированию на основе АТД, является, в некоторой степени, развитием тех идей о модульном программировании.
В ООП результатом абстракции являются объекты, представляющие собой абстрактные машины (устройства), обладающие внутренним состоянием, которое можно изменять посылкой сообщений через методы объекта. Объекты обмениваются сообщениями друг с другом и, таким образом, реализуется алгоритм программной модели.
Абстрактные типы данных позволяют достичь модульности программных продуктов и иметь несколько альтернативных взаимозаменяемых реализаций отдельного модуля.
Билет 11
Повторное использование, расширяемость, совместимость – как этого достичь.