1.Основные парадигмы программирования. Шения между ними, потом можно применять вопросы. Например, родственные отно
Скачать 102.69 Kb.
|
Парадигма программирования — совокупность идей и понятий, определяющая стиль написания программ. Парадигма является базовой программной единицей, в ка честве которой может выступать определение (декларативное, функциональное про граммирование), действие (императивное), объект (объектно-ориентированное) и дру гие сущности. В принципе, парадигмы программирования могут давать различный эффект для различных данных и ситуаций, то есть в каких-то случаях проще использовать логическое программирование, в каких-то функциональное, в каких-то объектноори ентированное. Если говорить в общем плане, то программирование делится на императив ное и декларативное. Императивная парадигма программирования описывает процесс вычисления в виде набора инструкций, меняющих состояние программы. Декларатив ная парадигма программирования описывает не процесс, а свойства какой-то базовой единицы. Декларативная парадигма программирования подразделяется, в основном, на функциональную и логическую. Функциональное программирование предполагает использование функций в их математическом смысле, то есть результат функции зависит только от входных пара метров и результатов других функций и не предполагает изменения состояния памяти. Среди наиболее известных языков для функционального программирования LISP, F#, SML, Haskell и т.д. Логическое программирование основано на математической логике. Парадиг ма хорошо подходит для решения задач, в которых действуют объекты и отношения между объектами, в частности, для задач искусственного интеллекта. Наиболее из вестный язык - Prolog. Например, сначала должны создать базу знаний (какие-то объекты и соотно шения между ними), потом можно применять вопросы. Например, родственные отно шения (рисунок 1) Вводится отношения между объектами, например: parent(tom, bob). parent(pam, bob). parent(tom, liz). parent(bob, ann). 1 Juli Ann Pat Mary Bob Liz Pam Tom Рис. 1. Схема родственных отношений parent(bob, pat). parent(mary, ann). parent(mary, pat). parent(pat, juli). Теперь можно задавать вопросы: ?- parent(tom, liz). yes ?- parent(tom,mary). no ?- parent(X,juli). X=pat и т. д. Императивное программирование развивалось постепенно, сюда входит про цедурное программирование, структурное, модульное, объектно-ориентированное. В принципе, наше лекции построены почти по тому же принципу. Рассмотрим эволюцию языков программирования и эволюцию технологий про граммирования. Процедурное программирование появилось вместе с первым программируемом компьютером, разработанным Конрадом Цузе в 1941 году. Это отражение архитек туры ЭВМ, предложенной фон Нейманом. Программа представляет собой последова тельность операторов (инструкций), задающих процедуру решения задачи. Основным является оператор присваивания, служащий для изменения содер жимого областей памяти. Концепция памяти как хранилища значений, содержимое которого может обновляться операторами программы, является фундаментальной в процедурном программировании. 2 Выполнение программы сводится к последовательному выполнению операто ров с целью преобразования исходного состояния памяти, то есть значений исходных данных, в заключительное, то есть в результаты. Таким образом, с точки зрения про граммиста имеются программа и память, причем первая последовательно обновляет содержимое последней. Процедурные языки характеризуются следующими особенностями: 1. Необходимостью явного управления памятью, в том числе через описание пере менных. 2. Малой пригодностью для символьных вычислений. 3. Отсутствием строгой математической основы. 4. Высокой эффективностью реализации на традиционных ЭВМ. Примером процедурной парадигмы может служить задача, разобранная на предыдущей лекции (Листинг ??). В 1970-ых годах, когда и задачи, и вычислительные машины стали усложнять ся, и интуитивная разработка программ перестала удовлетворять разработчиков, по явилась парадигма структурного программирования, предложенная Дейкстрой и Вир том. Основные положения структурного программирования: 1. Любая программа представляет собой структуру, построенную из трех базовых конструкций: Последовательное исполнение Однократное исполнение инструкций в том по рядке, в котором они записаны в программе. Ветвление Однократное исполнение операторов в зависимости от выполнения некоторого условия Цикл Многократное выполнение одной и той же операции до тех пор, пока выполняется некоторое условие. В программе эти конструкции могут быть вложены друг в друга каким-угодно образом, но других средств управления программой не предусматривается. 3 2. Повторяющиеся фрагменты программы, или не повторяющиеся, но представля ющие собой логические целостные вычислительные блоки, могут выделяться в отдельные подпрограммы. В этом случае в тексте основной программы вме сто помещенного в подпрограммы фрагмента вставляется инструкция вызова подпрограммы. При выполнении такой инструкции выполняется вызванная под программа, а потом исполнение программы продолжается с инструкции, распо ложенной после инструкции вызова подпрограммы. 3. Разработка программы ведется пошагово, методом «сверху вниз». Что имеется в виду. Сначала пишется текст основной программы, в которую вставляются все вызовы подпрограмм. Но вместо работающих подпрограмм ста вятся так называемые «заглушки», которые ничего не делают. После того, как отлажена основная программа, т. е., проверено, что все вызовы подпрограмм находятся на своих местах, начинают последовательно открывать заглушки, то есть заменять их на реально работающие подпрограммы, причем, разработка каждой подпрограммы ведется тем же способом. Таким образом, не может по лучится ошибки в месте, которое в данный момент находится вне поля зрения программиста. Например, задача о нахождении периметра и площади треугольника по коорди натам его точек. Алгоритм: а. Ввести координаты точек. б. Найти длины сторон треугольника. в. Проверить существует ли треугольник. г. Найти периметр. д. Найти площадь. Начинаем писать основную программу, поставив вместо подпрограмм заглушки: Листинг 0.1 1 #include 2 #include 4 3 using namespace std; 4 5 void point(float &x, float &y) //ввод координат точки 6 { 7 cout << "x="; 8 cin >> x; 9 cout << "y="; 10 cin >> y; 11 } 12 13 float dlina() 14 { 15 return 1; 16 } 17 18 float perimetr () 19 { 20 return 2; 21 } 22 23 float treug() 24 { 25 return 3; 26 } 27 28 float sqr() 29 { 30 return 4; 31 } 32 int main() 33 { 34 setlocale(LC_ALL, "Russian"); 35 float x1, x2, x3, y1, y2, y3; 36 cout << "Введите координаты 1 точки\n" 37 point(x1, y1); 38 cout << "Введите координаты 2 точки\n" 39 point(x2, y2); 40 cout << "Введите координаты 3 точки\n" 41 point(x3, y3); 5 42 float a, b, c; 43 a = dlina(); 44 cout << "a=" << a < b = dlina(); 46 cout << "b=" << b < c = dlina(); 48 cout << "c=" << c < float p, s; 50 if (treug()) 51 { 52 p = perimetr(); 53 s = sqr(); 54 cout << "p=" << p < cout << "s=" << s < } 57 else cout << "error"; 58 return 0; 59 } Результат работы программы: x1, y1 0 x2, y2 0 x3, y3 0 a=1 b=1 c=1 p=2 s=4 Результат нас удовлетворяет. Все работает последовательно. Начинаем с функ ции point, и т. д. В итоге получим такую программу: Листинг 0.2 1 #include 2 #include 3 using namespace std; 4 5 void point(float &x, float &y) //ввод координат точки 6 6 { 7 cout << "x="; 8 cin >> x; 9 cout << "y="; 10 cin >> y; 11 } 12 13 float dlina(float xa, float ya, float xb, float yb) //длина стороны 14 { 15 return sqrt((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb)); 16 } 17 18 float perimetr (float a, float b, float c) //периметр 19 { 20 return a + b + c; 21 } 22 23 bool treug(float a, float b, float c)//существование треугольника 24 { 25 if ((a + b > c) && (a + c > b) && (c + b > a)) return 1; 26 else return 0; 27 } 28 29 float sqr(float a, float b, float c) // формула Герона 30 { 31 float p = (a + b + c) / 2; 32 return sqrt(p * (p - a) * (p - b) * (p - c)); 33 } 34 35 int main() 36 { 37 setlocale(LC_ALL, "Russian"); 38 float x1, x2, x3, y1, y2, y3; 39 cout << "Введите координаты 1 точки\n"; 40 point(x1, y1); 41 cout << "Введите координаты 2 точки\n"; 42 point(x2, y2); 43 cout << "Введите координаты 3 точки\n"; 44 point(x3, y3); 7 45 float a, b, c; 46 a = dlina(x1, y1, x2, y2); 47 cout << "a=" << a < b = dlina(x2, y2, x3, y3); 49 cout << "b=" << b < c = dlina(x1, y1, x3, y3); 51 cout << "c=" << c < float p, s; 53 if (treug(a, b, c)) 54 { 55 p = perimetr(a, b, c); 56 s = sqr(a, b, c); 57 cout << "p=" << p < cout << "s=" << s < } 60 else cout << "error\n"; 61 return 0; 62 } Результат работы программы: Введите координаты 1 точки x=0 y=0 Введите координаты 2 точки x=1 y=0 Введите координаты 3 точки x=0 y=1 a=1 b=1.41421 c=1 p=3.41421 s=0.5 Так как введенный нами треугольник прямоугольный с координатами (0, 0), (1, 0) и (0, 1), то площадь действительно равна 0.5. Основные достоинства структурного программирования: 8 1. Структурное программирование позволяет значительно сократить число вари антов построения программы одной и той же спецификации, что существенно снижает сложность программы и облегчает понимание ее другими разработчи ками. 2. Логически связанные операторы находятся визуально ближе, а слабо связан ные — дальше, что позволяет обойтись без блок-схем и других графических форм изображения алгоритмов. 3. Существенно упрощается процесс тестирования и отладки программ. С усложнением проектов появилась идея модульного программирования. Это подразумевает что программа представляет собой набор независимых блоков (набор подпрограмм), каждая из которых имеет свой контролируемый размер, четкое назна чение и детально проработанный интерфейс с внешней средой. Каждая подпрограмма может быть разработана отдельно от других. Отлаженные подпрограммы помещаются в библиотеки подпрограмм. Так, во всех языках программирования появились обшир ные библиотеки подпрограмм. Развитие идей модульного программирования связано с именами Парнас, Коуэн и Цейтин. Достоинства: ∙ Успешно создаются достаточно крупные проекты. ∙ Уменьшается время разработки. ∙ Облегчается возможность модификации за счет использования стандартных под программ. Недостатки: ∙ Глобальные данные и неограниченность доступа к ним сильно усложняет струк туру программы и приводит к ошибкам. ∙ Очень трудоемкий процесс внесения любых, даже самых небольших изменений. И, наконец, модульное программирование не отражает картину реального ми ра. В итоге, пришли к идеям объектно-ориентированного программирования., основные положения были разработаны Кэйем и Ингаллсом. ООП использует идею 9 объединения данных и методов их обработки в специальные конструкции, получив шие название объектов. В качестве объекта может выступать что и кто угодно (люди, хранилища данных, типы данных и т. д.). Программа, разработанная на основе тех нологии ООП, представляет собой совокупность объектов, которые взаимодействуют посредством вызова подпрограмм друг друга. Упростить процесс написания программ по технологии ООП, позволяют такие понятия, как класс, объект, инкапсуляция, на следование и полиморфизм. Основное понятие — класс. С точки зрения компилятора класс является типом данных, определяемым пользователем. Класс объединяет в себе данные, методы для их обработки в сочетании с сокрытием ненужной для использования этих данных информацией. Это и есть инкапсуляция. Инкапсуляция повышает степень абстрак ции программы — для использования в программе какого-либо класса не требуется знаний о его реализации, необходимо только знать интерфейс (описание). Это позво ляет изменить реализацию класса, не затрагивая саму программу. Пример из жизни, например, пульт от телевизора выступает в роли интерфейса класса. Если нажать кнопку, то включается нужный канал, но как устроен процесс передачи включения канала знать не обязательно. Конкретные величины типа данных класс называются экземплярами класса или объектами. Например, создан класс «студент», в котором описаны такие поля, как ФИО, дата рождения, курс, оценки и т. д., а также методы: «показать данные», «перевести на следующий курс», «отчислить» и т. д. Объекты класса — это реальные студенты. У вес объектов данные будут различные, а методы их обработки одинако вые. Если изменится какое-нибудь правило, то достаточно изменить соответствующую подпрограмму в классе «студент» и это изменение отразится на методах всех объек тов. Например, были подпрограмма «отсчислить»: «Если два хвоста не сданы до опре деленного срока, то отчислить», сейчас «Если три хвоста не сданы до определенного срока, то отчислить». Изменили саму подпрограмму. Наследование — способность создавать производные классы, которые наследу ют все свойства своих предков, могут их изменять и создавать новые. При этом свойства не описываются заново, что сокращает объем программы. Еще один принцип, заложенный в основу ООП — полиморфизм, что позволяет в рамках одного класса или различных классов одного имени для обозначения сход 10 ных по смыслу действий и гибко выбирать требуемое действие во время выполнения программы. Например, базовый класс <<Млекопитающие >> Свойства: умеет дышать, питается молоком. Методы: может двигаться на четырех лапах. подкласс <<дельфин>> Свойства, унаследованные + похож на рыбу. Методы: может двигаться, но специфически (плавает) - полиморфизм подкласс <<человек>> Свойства, унаследованные + умеет говорить. Методы: может двигаться, но специфически (на двух ногах). Преимущества: 1. Логичность. ООП соответствует образу человеческого мышления (объекты, их характеристики и возможности), а не команды, переменные и операции. 2. Повторное использование кода в других приложениях. 3. Высокая скорость разработки за счет первых двух пунктов. В идеале, приложе ние не пишется, а собирается из готовых кусков с написанием незначительных по объему «связок». Есть и недостатки: 1. Большие временные затраты на проектирование, тормозит начальную фазу, но окупается на последующих этапах разработки ПО. 2. Снижение скорости работы приложения. Поддержка ООП требует больших за трат как по времени работы, так и по объему занимаемой памяти, по сравнению с другими технологиями. Рассмотрим теперь эволюцию языков программирования. По уровню языки программирования делятся на ∙ Языки низкого уровня. ∙ Языки высокого уровня. 11 Имеется ввиду не плохой или хороший язык, а близость оператора к машинному коду. Языком самого низкого уровня является ассемблер, который представляет каж дую команду машинного кода с помощью символьных условных обозначений, назы ваемых мнемониками. Однозначное преобразование одной машинной инструкции в одну команду процессора называется транслитерацией. Для каждой модели процес сора наборы инструкций отличаются, поэтому, программа, написанная на ассемблере, может быть использована только в этой среде, при этом еще и требуется очень хорошо понимать устройство компьютера. Языки высокого уровня разработаны для человека, они ему ближе и понятнее, поэтому, для перевода языка высокого уровня на машинный, созданы трансляторы. Они подразделяются на интерпретаторы и компиляторы. Интерпретатор берет очередной оператор языка из текста программы, ана лизирует его структуру и сразу исполняет. Только после того, как текущий оператор успешно выполнен, интерпретатор перейдет к следующему. При этом если один и тот же оператор должен выполняться многократно, интерпретатор будет каждый раз выполнять его, так как будто встретил впервые. Компилятор полностью обрабатывает весь текст программы, просматривает в поисках синтаксических ошибок, проводит смысловой анализ и автоматически пере водит весь текст на машинный язык, при этом нередко выполняется оптимизация с помощью набора методов, позволяющих повысить быстродействие программы. В ре зультате, законченная программа получается более компактной, работает в сотни раз быстрее, чем с помощью интерпретатора, и может быть перенесена на другие компью теры. Традиционно языки программирования делятся на пять поколений. Первое поколение — начало 50-ых годов на заре появления компьютеров. Прин цип «одна инструкция — одна строка» (первый ассемблер). Второе поколение — конец 50-ых — начало 60-ых. Появление «символического» ассемблера, где впервые появилось понятие переменной. Третье поколение — начало 70-ых. Появление универсальных языков програм мирования (Basic, Pascal, C/C++). Такие качества новых языков, как относительная простота, независимость от конкретного компьютера и использование мощных син таксических конструкций, позволили резко повысить производительность труда. 12 Четвертое поколение — ориентация на специализированные области примене ния, где хороших результатов можно добиться, используя не универсальные, а про блемно-ориентированные языки, оперирующие конкретными понятиями узкой пред метной области. Например, можно создавать базы данных с помощью структур в С++, но проще воспользоваться языком SQL. Сюда же относится язык HTML. Пятое поколение — середина 90-ых годов. Появление среды программирования .NET . Коды программ переводятся не в машинный код, а в некоторый промежуточный код, который затем выполняется «виртуальной машиной» конкретного компьютера, которая учитывает тип процессора и генерирует машинный код, соответствующий данному типу. Получаются платформно-независимые модули, которые легко работают не только на персональных компьютерах и мобильных устройствах, но и на серверах в локальных и глобальных сетях с различными операционными системами. Как видно, чтобы создать программу, достаточно самого простого редактора и транслятора. В действительности используются специальные среды разработки ПО, которые включают следующие компоненты: 1. Текстовый редактор для набора и редактирования текста 2. Отладчик, позволяющий анализировать работу программы во время ее выпол нения, что позволяет определять ошибки. 3. Редактор связей для сборки сложного проекта, подключения библиотек. 4. Транслятор для перевода исходного текста в машинный код. 5. Библиотеки стандартных подпрограмм. 6. Справочную систему. 7. Систему подсказок. 13 |