Что такое парадигмы программирования и зачем они нужны
Знакомство с новыми парадигмами программирования может перевернуть вашу точку зрения на написание кода. Рассказываем, что это такое.
Парадигма программирования — это набор идей и понятий, которые определяют стиль написания программ, подход к программированию. Существует множество разных парадигм, но чаще всего используются императивная и декларативная, практически противоположные друг другу.
Императивная парадигма программирования
В императивной (англ. imperative — приказ) парадигме разработчик пишет для компьютера инструкции, которым тот следует. Инструкции могут быть следующие:
То есть программист говорит, что нужно сделать и в каком порядке, а компьютер выполняет приказы.
Отличительная черта императивной парадигмы — понятие состояния компьютера или программы. Состояние — это совокупность всех данных в определённый момент времени: переменных, массивов, счётчиков и так далее.
К императивной парадигме относятся следующие виды программирования:
Также императивную парадигму программирования можно считать более низкоуровневой, потому что программисту нужно знать, как работают программы.
Декларативная парадигма программирования
В декларативной парадигме разработчик описывает проблему и ожидаемый результат, но не пишет никаких инструкций. В декларативном программировании отсутствуют переменные, состояние и прочие понятия, которые свойственны императивной парадигме.
К декларативной парадигме относятся функциональное и логическое программирование.
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Примеры использования парадигм
Допустим, у нас есть массив следующих чисел:
Нам может понадобиться получить из этого массива все числа, которые больше 3, но меньше 100.
В декларативном программировании разработчик просто пишет следующее:
Программист не думает о том, как программа будет искать эти числа, он просто пишет, какой результат ему нужен.
В императивном программировании придётся самостоятельно написать код, который будет проверять все числа из массива N на соответствие условию и, если они подходят, записывать их в новый массив. То есть код будет выглядеть примерно так:
То есть в декларативном программировании разработчик говорит, что ему нужно. А в императивном — как это можно получить.
Давайте рассмотрим это на примере двух реальных языков:
for(int i = 0; i 3 && N[i] 3 AND num Зачем это нужно
У вас мог появиться вполне логичный вопрос:
Зачем использовать императивное программирование, если декларативное позволяет писать гораздо меньше кода?
Есть несколько причин.
Во-первых, декларативное программирование — это обёртка для императивного. Компьютер не может вот так просто понять, чего хочет программист, поэтому для него нужно написать конкретные инструкции, что и в каком порядке делать.
Когда вы пишете запрос в SQL, его выполнение происходит по заранее описанным инструкциям. Поэтому нам нужно императивное программирование, чтобы заставить работать декларативное.
Во-вторых, декларативное программирование не подходит для задач, для решения которых важно иметь доступ к состоянию программы — например, если нужно проверить, нажата ли кнопка или поставлена ли галочка в чекбокс.
В декларативном программировании нельзя отследить ни само состояние, ни его изменение, поэтому не получится указать, что должно происходить в ответ на действия пользователя.
В-третьих, императивное программирование даёт больше свободы, поэтому его чаще используют в творческих областях, особенно там, где важен порядок выполняемых действий.
Каждая парадигма подходит для определённых задач: императивная лучше для работы с анимацией, графическими интерфейсами, скриптами, играми и многим другим, а декларативная — для вычислений и работы с данными. Поэтому вопрос «Какая парадигма лучше?» некорректен: они все хороши, если использовать их по назначению.
Заключение
Большинство языков поддерживают обе парадигмы, но заточены под одну из них. Один из таких языков — C#. Несмотря на то что это объектно-ориентированный язык программирования (императивная парадигма), в нём присутствуют элементы функциональной разработки (декларативная разработка).
Освоить этот язык, особенности ООП, а также ознакомиться с функциональной разработкой вы можете на курсе «Профессия C#-разработчик».
Парадигмы программирования: определение, виды и их особенности
Парадигмы программирования
Если представить условную иерархию, тогда парадигмы программирования будут на самой вершине. Именно они будут определят ь п равила написания, свойства, шаблоны, паттерны, структуру, архитектуру программы и др. То ест ь и значально идет парадигма, которая влечет все остальные собственные составляющие.
Объектно-ориентированному программированию свойственны такие принципы, как:
Парадигма функционального программирования
Парадигма функционального программирования заняла почетное второе место по популярности после объектно-ориентированного программирования. Главная идея такой модели заключается в том, что программа создается под одну конкретную задачу, поэтому от нее ждут конкретный результат.
В ООП основной компонент программы — объект. В функциональном программировании — функция. В функциях прописывается, какую информацию она должна получить в качестве входящего значения, а какую должна отдать. Функции могут быть вложенными — это когда одна функция является аргументом другой функции.
Программы, написанные по такой модели, обычно легче тестировать и читать, если сравнивать с ООП.
Процедурная парадигма программирования
Процедурная парадигма программирования основывается на процедурах. Процедура — это инструкция, которая используется для воздействи я на состояние памяти. После исполнения всего набора инструкци й п рограмма выдает результат.
Парадигма декларативного программирования
В такой парадигме программист описывает проблему и ожидаемый результат, но не дает инструкций программе, как достичь этого результата. В таком подходе отсутствуют переменные, состояния программы и операторы присваивания.
Логическая парадигма программирования
Такой вид программирования используется языками Prolog и Planner.
Национальная библиотека им. Н. Э. Баумана Bauman National Library
Персональные инструменты
Парадигма программирования
Парадигма программирования – это совокупность принципов, методов и понятий, определяющих способ конструирования программ.
Парадигма (философия науки) – устоявшаяся система научных взглядов, в рамках которой ведутся исследования (Т. Кун).
Язык программирования не обязательно использует только одну парадигму. Языки, поддерживающие несколько парадигм, называются мультипарадигменными. Создатели таких языков придерживаются точки зрения, гласящей, что ни одна парадигма не может быть одинаково эффективной для всех задач, и следует позволять программисту выбирать лучший стиль программирования для решения каждой отдельной задачи.
Содержание
История
Своим современным значением в научно-технической области термин «парадигма» обязан, по-видимому, Томасу Куну и его книге «Структура научных революций». Кун называл парадигмами устоявшиеся системы научных взглядов, в рамках которых ведутся исследования. Согласно Куну, в процессе развития научной дисциплины может произойти замена одной парадигмы на другую, при этом старая парадигма ещё продолжает некоторое время существовать и даже развиваться благодаря тому, что многие её сторонники оказываются по тем или иным причинам неспособны перестроиться для работы в другой парадигме.
Термин «парадигма программирования» впервые применил в 1978 году Роберт Флойд в своей лекции лауреата премии Тьюринга. Флойд отмечает, что в программировании можно наблюдать явление, подобное парадигмам Куна, но, в отличие от них, парадигмы программирования не являются взаимоисключающими: если прогресс искусства программирования в целом требует постоянного изобретения и усовершенствования парадигм, то совершенствование искусства отдельного программиста требует, чтобы он расширял свой репертуар парадигм.
Таким образом, по мнению Роберта Флойда, в отличие от парадигм в научном мире, описанных Куном, парадигмы программирования могут сочетаться, обогащая инструментарий программиста.
Важно отметить, что парадигма программирования не определяется однозначно языком программирования; практически все современные языки программирования в той или иной мере допускают использование различных парадигм. Так на языке Си, который не является объектно-ориентированным, можно работать в соответствии с принципами объектно-ориентированного программирования, хотя это и сопряжено с определёнными сложностями; функциональное программирование можно применять при работе на любом императивном языке, в котором имеются функции (для этого достаточно не применять присваивание). [Источник 2]
Разновидности парадигмы
Парадигма программирования не определяется однозначно языком программирования; практически все современные языки программирования в той или иной мере допускают использование различных парадигм.
Так на языке Си, который не является объектно-ориентированным, можно работать в соответствии с принципами объектно-ориентированного программирования, хотя это и сопряжено с определёнными сложностями; функциональное программирование можно применять при работе на любом императивном языке, в котором имеются функции (для этого достаточно не применять присваивание), и т.д.
Императивное программирование
Императивные парадигмы программирования представляют программу как последовательность действий (операторов), которые преобразуют состояние программы. Допустимые виды операторов, а также типы обрабатываемых данных определяются конкретным языком программирования. К императивным парадигмам относится процедурная парадигма программирования., в которой отдельные группы часто повторяемых операторов выделяются в процедуры (называемые также подпрограммами), описывающие действия по переводу одних данных в другие. В число операторов таких языков входит оператор обращения к процедуре.
Основные механизмы управления/абстракции:
Структурное программирование
Структурные парадигмы программирования нацелены на сокращение времени разработки и упрощение поддержки программ за счёт использования блочных операторов и подпрограмм. Отличительной чертой структурных программ является отказ от оператора перехода (goto).
Основные механизмы управления/абстракции:
Элементарные единицы модульности:
Объектно-ориентированное программирование
Основные механизмы управления/абстракции:
Функциональное программирование
Представление программы в форме набора чистых функций, порождающих результаты на основе входных данных.
Основные механизмы управления/абстракции:
Элементарные единицы модульности:
Неподвижное состояние объектов
При инициализации идентификатора (переменной) ему сопоставляется некоторое значение (объект), которое не может быть изменено. При этом идентификатор с тем же самым именем может быть определен в другом лексическом контексте с другим значением.
Чистая функция (pure function) – функция не имеющая побочных эффектов, т.е. единственным эффектом ее применение является порождение результата, зависящего только от аргументов. [Источник 3]
Логическое программирование
Логическое программирование начинает свой отсчет времени с конца 60-х годов XX века, когда Корделл Грин предложил использовать резолюцию как основу логического программирования. Алан Колмеро создал язык логического программирования Prolog в 1971 году. Логическое программирование пережило пик популярности в середине 80-х годов XX века, когда оно было положено в основу проекта разработки программного и аппаратного обеспечения вычислительных систем пятого поколения.
Важным преимуществом такого подхода является достаточно высокий уровень машинной независимости, а также возможность откатов – возвращения к предыдущей подцели при отрицательном результате анализа одного из вариантов в процессе поиска решения.
Одним из недостатков логического подхода в концептуальном плане является специфичность класса решаемых задач.
Другой недостаток практического характера состоит в сложности эффективной реализации для принятия решений в реальном времени, скажем, для систем жизнеобеспечения.
Нелинейность структуры программы является особенностью декларативного подхода и, строго говоря, представляет собой оригинальную особенность, а не объективный недостаток. [Источник 4]
Подходы и приёмы
Далее будут представлены более подробно подходы и приемы парадигмы программирования:
Структурное программирование
Cтруктурное программирование воплощает принципы системного подхода в процессе создания и эксплуатации программного обеспечения ЭВМ. В основу структурного программирования положены следующие достаточно простые положения:
Фундаментом структурного программирования является теорема о структурировании. Эта теорема устанавливает, что, как бы сложна ни была задача, схема соответствующей программы всегда может быть представлена с использованием ограниченного числа элементарных управляющих структур. Базовыми элементарными структурами являются структуры: следование, ветвление и повторение (цикл), любой алгоритм может быть реализован в виде композиции этих трех конструкций. [Источник 5]
Обобщённое программирование
Процедурное (алгоритмическое) программирование
Преимущества и недостатки процедурного программирования: Среди недостатков ПП можно назвать следующие:
Доказательное программирование
Доказательное программирование — это составление программ с доказательством их правильности. Сложность составления и доказательства правильности алгоритмов и программ состоит в следующем.
Для заключений о наличии ошибок в алгоритме или в программе достаточно указать тест, при котором произойдет сбой, отказ или будут получены неправильные результаты.
Поиск и исправление ошибок в программах обычно проводятся на ЭВМ. Для утверждений о правильности программ необходимо показать, что правильные результаты будут получаться для всех допустимых данных. Такие утверждения могут быть доказаны только путем исчерпывающего анализа результатов выполнения программ при любых допустимых данных.
Существуют два подхода к проверке программ — прагматический и доказательный. При прагматическом подходе проверка программ выполняется на ЭВМ путем тестирования.
Тестирование — это проверка программ на ЭВМ с помощью некоторого набора тестов. Ясно, что тестирование не дает гарантий правильности выполнения программ на всех допустимых данных. Следовательно, тестирование в общем случае не может дать и не дает полных гарантий отсутствия ошибок в программах.
Напомним, что отладка программ — это процесс поиска и исправления ошибок в программах на ЭВМ. Однако поскольку поиск ошибок при отладке программ проводится с помощью тестов, то полных гарантий нахождения и исправления всех ошибок в программах отладка не дает и в принципе дать не может.
По этой же причине неясно, когда процесс отладки программ — процесс поиска и исправления ошибок на ЭВМ — может считаться завершенным. А выявлены или нет все ошибки в программе при ее отладке не может сказать никто.
Таким образом, прагматический подход чреват созданием программ, содержащих ошибки даже после «завершения» отладки, что и наблюдается практически во всех больших программах для ЭВМ. [Источник 8]
Порождающее программирование
Порождающее программирование (generative programming) – парадигма технологии разработки программного обеспечения, основанная на моделировании семейства программных систем, используя которые можно по конкретным техническим требованиям автоматически получить специализированный и оптимизированный промежуточный или конечный программный продукт из элементарных, многократно используемых компонентов реализации с помощью базы знаний о конфигурациях.
Порождающее программирование фокусирует внимание не на уникальных продуктах (объектах), а на семействах программных систем (классах объектов). Таким образом, порождающее программирование имеет огромное сходство с теорией универсальных и интегративных моделей, применяемых для синтеза объектов, и являющихся моделями не отдельно взятого объекта, а моделями всех объектов, принадлежащих рассматриваемому классу (моделью семейства объектов или систем). [Источник 9]
Аспектно-ориентированное программирование
Аспектно-ориентированное программирование(АОП) — это парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули.
Аспектно-ориентированное программирование выросло из осознания того, что в типовых программах на объектно-ориентированных языках часто представлена функциональность, которая не вмещается естественно в один или даже в несколько тесно связанных программных модулей. Такую функциональность называют «сквозной» (англ. scattered, разбросанная или tangled, переплетённая), её реализация рассыпана по различным модулям программы. Сфера действия АОП охватывает пространство проблем, непосильных для объектно-ориентированных и процедурных языков. Оно предлагает элегантные пути для реализации задач, решение которых сдерживалось из-за фундаментальных ограничений программирования.
АОП дополняет объектно-ориентированное программирование, обогащая его другим типом модульности, который позволяет локализовать код реализации «сквозной» логики в одном модуле. Такие модули обозначаются термином аспекты. За счет отделения аспектно-ориентированного кода работа со «сквозными» отношениями упрощается. Аспекты в системе могут изменяться, вставляться, удаляться на этапе компиляции и, более того, повторно использоваться. [Источник 10]
Рекурсия
В программировании рекурсия тесно связана с функциями, точнее именно благодаря функциям в программировании существует такое понятие как рекурсия или рекурсивная функция. Простыми словами, рекурсия – определение части функции (метода) через саму себя, то есть это функция, которая вызывает саму себя, непосредственно (в своём теле) или косвенно (через другую функцию).
У рекурсии должно быть условие остановки — Базовый случай (иначе также как и цикл рекурсия будет работать вечно — infinite). Это условие и является тем случаем к которому рекурсия идет (шаг рекурсии). При каждом шаге вызывается рекурсивная функция до тех пор пока при следующем вызове не сработает базовое условие и произойдет остановка рекурсии(а точнее возврат к последнему вызову функции). Всё решение сводится к решению базового случая. В случае, когда рекурсивная функция вызывается для решения сложной задачи (не базового случая) выполняется некоторое количество рекурсивных вызовов или шагов, с целью сведения задачи к более простой. И так до тех пор пока не получим базовое решение. [Источник 11]
Автоматное программирование
Автоматное программирование поддерживает такие этапы создания программного обеспечения как проектирование, реализация, отладка и документирование.
Особенность рассматриваемого подхода состоит в том, что при его использовании автоматы задаются графами переходов, для различения вершин в которых вводится понятие «кодирование состояний». При выборе «многозначного кодирования» с помощью одной переменной можно различить состояния, число которых совпадает со значностью выбранной переменной. Это позволило ввести в программирование такое понятие, как «наблюдаемость программ».
В рамках предлагаемого подхода программирование выполняется «через состояния», а не «через переменные» (флаги), что позволяет лучше понять и специфицировать задачу и ее составные части.
При этом необходимо отметить, что в автоматном программировании отладка проводится путем протоколирования в терминах автоматов. [Источник 12]
Событийно-ориентированное программирование
Идеология здесь основана на событиях (нажал клавишу, меню щелк). В ответ в windows генерируется подходящее сообщение, которое отсылается окну соответствующей программы.
Структура программы в событийном программировании следующая: главная часть программы представляет собой один бесконечный цикл, который опрашивает windows, следя за тем, не появилось ли новое сообщение. При его обнаружении вызывается программа, отвечающая за обработку соответственного сообщения. Цикл опроса будет продолжаться, пока не будут получены сообщения завершения работы.
События могут быть пользовательскими, системными и программными, которые генерируются самой программой. [Источник 13]
Компонентно-ориентированное программирование
Компонентно-ориентированное программирование (англ. component-oriented programming, COP) — парадигма программирования, существенным образом опирающаяся на понятие компонента — независимого модуля исходного кода программы, предназначенного для повторного использования и развёртывания и реализующегося в виде множества языковых конструкций (например, «классов» в объектно-ориентированных языках программирования), объединённых по общему признаку и организованных в соответствии с определёнными правилами и ограничениями. [Источник 14]
Грамотное программирование
Грамотное, или литературное, программирование – это экстремальная технология самодокументируемого кода, предложенная знаменитым специалистом в вычислительной технике Дональдом Кнутом. Он написал книгу под этим названием, в которой и описал эту технологию (Knuth 92). Это радикальная альтернатива традиционной модели программирования, хотя некоторые считают, что период грамотного программирования был крупной неудачей в карьере Д. Кнута.
Лежащая в основе идея проста: нужно писать не программу, а документ. Язык документации тесно привязан к языку программирования. Ваш документ в основном описывает то, что программируется, но при этом допускает компиляцию в нужную программу. Таким образом, исходный код – это документация, и наоборот. [Источник 15]
Ну что же, приступим. Скорее всего, многим данное словосочетание покажется пугающим, но, на самом же деле, здесь нет ничего сложного. Что же такое “Парадигма программирования”? Возьмем определение из википедии: “Парадигма программирования – это совокупность идей и понятий, определяющих стиль написания компьютерных программ (подход к программированию). Это способ концептуализации, определяющий организацию вычислений и структурирование работы, выполняемой компьютером”.
Если говорить самым простым языком, то парадигмапрограммирования – это подход к написанию кода. Читатели без опыта программирования, вероятнее всего, зададутся вопросами: “А что это за такие подходы? То есть, например, ты пишешь код сначала левой рукой, потом правой? Или же ты пишешь код час, а потом полчаса отдыхаешь? Что это за подходы?!”. На самом же деле, подходы подразумевают под собой совсем другое и далеки от примеров, описанных до этого.
Чтобы понять, что это такое, давайте рассмотрим два основных подхода, то есть две основные парадигмы: Объектно-ориентированное программирование (ООП) и Функциональное программирование (ФП). ООП основано на том, что все можно представить в виде объектов, у которых могут быть какие-то характеристики (поля) и они могут выполнять какие-то действия (методы/функции). ФП же основано на описание процессов (функций), а не объектов. Понимаю, пока не понятно, поэтому давайте разберем простейший пример. Представим, что нам нужно как-то складывать и вычитать два числа (a и b). На картинке ниже представлен код, реализующий это в ООП и ФП (код был специально упрощен, чтобы сделать упор именно на разнице двух подходов). Вы сразу можете заметить функции “sum” (сложение) и “subtract” (вычитание), которые мы хотели реализовать.
— Так, ну функции я вижу, а почему в ООП есть еще “class Calculator”, что это значит?
Как уже было сказано выше, ООП основано на том, что все можно представить в виде объектов: например, есть объект “Вселенная”, она состоит из галактик (объект “Галактика”), та, в свою очередь, состоит из планет (объект “Планета”), на каждой планете могут быть люди (объект “Человек”) и так далее. Возьмем, например, объект “Человек”, его характеристиками (полями) могут быть: цвет кожи, пол, рост, возраст (что-то еще). И также он может выполнять следующие действия (методы/функции): бегать, кушать, работать и так далее. Вы легко можете спроецировать такой подход (парадигму) на жизнь, представить все вокруг с помощью объектов и вы поймете, что любое действие (метод/функция) связано с каким-либо объектом, оно не может существовать само по себе, кто-то должен его выполнять. Именно по этой причине наши действия (методы/функции) “sum” и “subtract” находятся внутри объекта “Calculator” (Калькулятор).
— Интересно! Про ООП я понял, а почему в ФП все функции ни к чему не привязаны, находятся сами по себе?
Помните я говорил, что ФП основано на процессах (функциях)? Давайте опять попробуем спроецировать это на нашу жизнь. Например, возьмем процесс (функцию) создания вселенной, галактики, планеты, человека, процесс (функцию) сложения, вычитания и т.д. Сам процесс (функция) никому не принадлежит — он общий, пользоваться может кто угодно, но при этом каждый процесс (функция) имеет определенные условия, в зависимости от которых получается тот или иной результат. Рассмотрим простой пример из жизни, процесс “Приготовление ужина”: данный процесс может осуществить кто угодно, даже ваш кот или собака, но так как опыта у них нет, то, вероятнее всего, ужин просто не будет приготовлен. То есть получается, что воспользоваться могут все, но результат будет разный.
— Фух, ну теперь понятно, что такое парадигма программирования. Ну все-таки остался вопрос: почему где-то используется одна парадигма, а где-то другая?
Вы удивитесь, но на самом деле, две эти парадигмы можно использовать одновременно. Опять-таки, давайте рассмотрим простой пример, спроецированный на реальную жизнь. Представим, что у нас есть:
Заключение
Итак, в этой статье мы можно сказать на пальцах, без специфических терминов, разобрали основные различия парадигм ООП и ФП. К сожалению, тут нам пора остановиться. Теперь ваш ход – самостоятельно углублять знания с помощью дополнительной литературы.
Должен сказать, что я немного творчески подошел к написанию данной статьи: упростил терминологию, а где-то и вовсе заменил понятия метафорами, но все это только для того, чтобы любой человек, даже не имеющий никаких знаний в этой области, мог погрузиться в тему парадигм программирования. Я надеюсь, что данная статья была полезна будущем программистам и после ее прочтения удивительный мир программирования стал чуть ближе для каждого.