Содержание Лабораторная работа № 1 ....................................................................................... 3 Лабораторная работа № 2 ....................................................................................... 8 Лабораторная работа № 3 ..................................................................................... 11 Лабораторная работа № 4 ..................................................................................... 15 Лабораторная работа № 6 ..................................................................................... 22 Лабораторная работа № 7 ..................................................................................... 25 Лабораторная работа № 8 ..................................................................................... 28 2 Лабораторная работа № 1 Описание, анализ и разработка структуры программ. Лексемы и разделители. Элементарные типы данных. Переменные. Типы переменных. Выражения и оператор присвоения. Контроль типов данных. Организация ввода-вывода. Группа 1-5М. Костюк А.А., Амзаев А.А, Дорошенко А. Цель работы: получить навыки в описании, анализе, разработке структуры программы и основных понятиях. Ход работы: В процессе создания любой программы можно выделить несколько этапов: 1. Постановка задачи – выполняется специалистом в предметной области на естественном языке. Необходимо определить цель задачи, ее содержание и общий подход к решению. Уже на этапе постановки надо учитывать эффективность алгоритма решения задачи на ЭВМ, ограничения, накладываемые аппаратным и программным обеспечением. 2. Анализ задачи и моделирование – определяются исходные данные и результат, выявляются ограничения на их значения, выполняется формализованное описание задачи и построение (выбор) математической модели, пригодной для решения на компьютере. 3. Разработка или выбор алгоритма решения задачи – выполняется на основе ее математического описания. Многие задачи можно решить различными способами. Программист должен выбрать оптимальное решение. Неточности в постановке, анализе задачи или разработке алгоритма могут привести к скрытой ошибке. 3 4. Проектирование общей структуры программы – формируется модель решения с последующей детализацией и разбивкой на подпрограммы, определяется "архитектура" программы, способ хранения информации. 5. Кодирование – запись алгоритма на языке программирования. 6. Отладка и тестирование программы. Под отладкой понимается устранение ошибок в программе. Тестирование позволяет вести их поиск и, в конечном счете, убедиться в том, что полностью отлаженная программа дает правильный разрабатывается система тестов результат. Для – специально этого подобранных контрольных примеров – с такими наборами параметров, для которых решение задачи известно. 7. Анализ результатов — если программа выполняет моделирование какого-либо известного процесса, следует сопоставить результаты вычислений с результатами наблюдений. 8. Публикация и документация. Объектно-ориентированное программирование (ООП) – методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования. Примеры ООП языков: ‒ TypeScript (надстройка ООП над JS от Microsoft); ‒ C; ‒ C++; ‒ C#; ‒ Java. Лексема – это последовательность из одного или несколько символов, представляющая определенный смысл. 4 Лексемам в языке человека соответствует понятие слово. В литературе, посвященной трансляции с языков программирования, часто используется термин токен, имеющий тот же смысл. Существует несколько видов лексем: ‒ идентификаторы (имена объектов – последовательность букв, цифр и символов подчеркивания); ‒ ключевые (зарезервированные, служебные) слова; ‒ знаки операций (константа, переменная или вызов метода); ‒ разделители (используются для разделения или для группировки элементов. Примеры разделителей: пробелы, скобки, точка, запятая); ‒ литералы (это величины, которые неизменны. Короче говоря константы). Элементарные типы данных – такие типы, которые приводят определенную объявленную переменную к определенному типу (к примеру, в языке Java есть такие элементарные типы данных: byte, short, int, long, char, float, double и boolean). Переменная – поименованная, либо адресуемая иным способом область памяти, адрес которой можно использовать для осуществления доступа к данным и изменять значение в ходе выполнения программы. Если говорить понятным, человеческим, языком, то переменная – это такая коробка, в которую можно запихнуть объект данных, ссылку или другое. В статическом языке программирования (С, С++, С#, Java) как правило объявленная переменная неизменна по своему типу данных (исключение С#. Об этом чуть далее). В динамическом языке программирования (Python, JavaScript) переменная необязательно должна содержать определенный тип данных и в нее можно пихать как string, так и int с одним только условием – прежние данные, содержащиеся в «коробке» переменной, начисто стираются новыми данными. Из статических языков, в C# есть тип данных dynamic который объявляет переменную как динамическую. 5 Типы переменных бывают разные: ‒ String – строка, содержащая слова или предложения символами юникода; ‒ Int – целочисленные значения; ‒ Double – дробное значение; ‒ Char – символьный тип и т.д.; В зависимости от языка программирования (статического или динамического), переменная бывает неизменна по своему типу или же наоборот изменяема. Выражением называется совокупность переменных, констант, знаков операций, имен функций, скобок, которая может быть вычислена в соответствии с синтаксисом языка программирования. Результатом вычисления выражения является величина определенного типа. Оператор присваивания представляет собой запись, содержащую символ = (знак равенства), слева от которого указано имя переменной, а справа – выражение. Большинство традиционных императивных и объектно- ориентированных языков программирования ориентировано на повсеместное применение статического контроля типов (в период компиляции). Необходимые при этом сведения частично поступают из явных объявлений. Перечислим исходные данные, необходимые для организации статического контроля типов: ‒ для каждой операции определены количество и типы данных для операндов и результата; ‒ тип каждого объекта данных (переменной или экземпляра типа) известен и не меняется в ходе выполнения программы; 6 ‒ типы всех констант тоже понятны. Тип литерала легко определяется из синтаксиса его записи в тексте программы, а тип именованной константы зафиксирован в ее определении. Организация ввода-вывода данных возможна определенными командами на языке программирования, к примеру WriteLine() запись данных, ReadLine() их считывание. В зависимости данные записываются в файл, выводятся на консоль, в веб-форму, интерфейс и так далее в зависимости от того куда эти данные были выведены. Вывод: в процессе выполнения лабораторной работы были получены навыки в описании, анализе, разработке структуры программы и основных понятиях в языке программирования Java. 7 Лабораторная работа № 2 Работа с объектно-ориентированной моделью Костюк А.А., Амзаев А.А., Дорошенко А.В. группа 1-5М Цель работы: получить навыки в работе с объектно-ориентированной моделью на языке Java. Ход работы: Объектно-ориентированная модель представления данных дает возможность идентификации отдельных записей базы. Записи базы данных и функции их обработки связаны механизмами, подобными соответствующим средствам, которые реализуются в объектноориентированных языках программирования. Графическим представлением структуры объектно-ориентированной базы данных является дерево, узлы которого представляют объекты. При выполнении действий над данными в объектно-ориентированной модели используются логические операции, которые усилены инкапсуляцией, наследованием и полиморфизмом. С некоторым ограничением можно применять операции, которые подобны командам SQL (например, при создании БД). Основные понятия ООП применительно к объектно-ориентированной модели БД: Инкапсуляция ограничивает область видимости имени свойства пределами того объекта, в котором оно определено. Так, если в объект тина добавить свойство, то мы получим одноименные свойства. Смысл такого свойства будет определяться тем объектом, в который оно инкапсулировано. Наследование, наоборот, распространяет область видимости свойства на всех потомков объекта. Так, всем объектам, являющимся потомками объекта другого типа, можно приписать свойства объекта-родителя. Если необходимо расширить действие механизма наследования на объекты, не являющиеся 8 непосредственными родственниками (например, между двумя потомками одного родителя), то в их общем предке определяется абстрактное свойство. Полиморфизм в объектно-ориентированных языках программирования означает способность одного и того же программного кода работать с разнотипными данными. Другими словами, он означает допустимость в объектах разных типов иметь методы (процедуры или функции) с одинаковыми именами. Во время выполнения объектной программы одни и те же методы оперируют с разными объектами в зависимости от типа аргумента. Достоинства: Возможность отображения информации о сложных взаимосвязях объектов. Объектно-ориентированная модель данных позволяет идентифицировать отдельную запись базы данных и определять функции их обработки. Недостатки: Высокая понятийная сложность, неудобство обработки данных и низкая скорость выполнения запросов. Код программы: public abstract class AbstractPhone { private int year; public AbstractPhone(int year) { this.year = year; } public abstract void call(int outputNumber); public abstract void ring(int inputNumber); } public class SomePhone { private int year; private String company; public SomePhone(int year, String company) { this.year = year; this.company = company; } private void openConnection() { //findComutator //openNewConnection... } public void call() { openConnection(); System.out.println("Вызываю номер"); } 9 public void ring() { System.out.println("Дзынь-дзынь"); } } В нашей программе использование данной модели представим в виде рисунка 1. Рисунок 1. Объектно-ориентированная модель В нашем приложением мы не используем БД в её стандартном понимании, но храним значения переменных и объектов, присваивая им определенные теги (аналог имени в БД). Таким образом, при вызове определенного метода мы обращаемся к объектам через определенный тег. Вывод: в процессе выполнения лабораторной работы были получены навыки в работе с объектно-ориентированной моделью. 10 Лабораторная работа № 3 Средства объектного и объектно-ориентированного программирования языка Java Костюк А.А., Амзаев А.А., Дорошенко А.В. группа 1-5М Цель работы: получить навыки в средствах объектно- ориентированного программирования языка Java. Ход работы: Объектно-ориентированное программирование (ООП) – это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования. Класс – это шаблон, описание ещё не созданного объекта. Класс содержит данные, которые описывают строение объекта и его возможности, методы работы с ним. Объект – экземпляр класса. То, что «рождено» по «чертежу», то есть по описанию из класса. На каждом этапе развития программирования появлялись методы и инструментальные средства для обуздания неуклонно растущей сложности программ. И на каждом таком этапе новый подход вбирал в себя все самое лучшее из предыдущих, знаменуя собой прогресс в программировании. Это же можно сказать и об ООП. До ООП многие проекты достигали (а иногда и превышали) предел, за которым структурный подход к программированию оказывался уже неработоспособным. Поэтому для преодоления трудностей, связанных с усложнением программ, и возникла потребность в ООП. ООП вобрало в себя все самые лучшие идеи структурного программирования, объединив их с рядом новых понятий. В итоге появился новый и лучший способ организации программ. В самом общем виде программа может быть организована одним из двух способов: вокруг кода (т.е. 11 того, что фактически происходит) или же вокруг данных (т.е. того, что подвергается воздействию). Программы, созданные только методами структурного программирования, как правило, организованы вокруг кода. Такой подход можно рассматривать как “как код, воздействующий на данные”. Совсем иначе работают объектно-ориентированные программы. Они организованы вокруг данных, исходя из главного принципа: “данные управляют доступом к коду”. В объектно-ориентированном языке определяются данные и код, которому разрешается воздействовать на эти данные. Следовательно, тип данных точно определяет операции, которые могут быть выполнены над данными. Для поддержки принципов ООП все объектно-ориентированные языки программирования, в том числе и Java, должны обладать тремя общими свойствами: ‒ Инкапсуляцией: Инкапсуляция – это механизм программирования, объединяющий вместе код и данные, которыми он манипулирует, исключая как вмешательство извне, так и неправильное использование данных; ‒ Полиморфизмом: Полиморфизм (по-гречески «множество форм») – это свойство, позволяющее одному интерфейсу получать доступ к общему классу действий; ‒ Наследованием: Наследование-представляет собой процесс, входе которого один объект приобретает свойства другого объекта. Код программы: public abstract class WirelessPhone extends AbstractPhone { private int hour; public WirelessPhone(int year, int hour) { super(year); this.hour = hour; } } 12 public class CellPhone extends WirelessPhone { public CellPhone(int year, int hour) { super(year, hour); } @Override public void call(int outputNumber) { System.out.println("Вызываю номер " + outputNumber); } @Override public void ring(int inputNumber) { System.out.println("Вам звонит абонент " + inputNumber); } } public class Smartphone extends CellPhone { private String operationSystem; public Smartphone(int year, int hour, String operationSystem) { super(year, hour); this.operationSystem = operationSystem; } public void install(String program) { System.out.println("Устанавливаю " + program + "для" + operationSystem); } } public class User { private String name; public User(String name) { this.name = name; } public void callAnotherUser(int number, AbstractPhone phone) { // вот он полиморфизм - использование в коде абстактного типа AbstractPhone phone! phone.call(number); } } } public class ThomasEdisonPhone extends AbstractPhone { public ThomasEdisonPhone(int year) { super(year); } @Override public void call(int outputNumber) { System.out.println("Вращайте ручку"); System.out.println("Сообщите номер абонента, сэр"); 13 } @Override public void ring(int inputNumber) { System.out.println("Телефон звонит"); } } AbstractPhone firstPhone = new ThomasEdisonPhone(1879); AbstractPhone phone = new Phone(1984); AbstractPhone videoPhone = new VideoPhone(2018); User user = new User("Андрей"); user.callAnotherUser(224466, firstPhone); // Вращайте ручку //Сообщите номер абонента, сэр user.callAnotherUser(224466, phone); //Вызываю номер 224466 user.callAnotherUser(224466, videoPhone); //Подключаю видеоканал для абонента 224466 Вывод: в процессе выполнения лабораторной работы были получены навыки в средствах объектно-ориентированного программирования языка Java. 14 Лабораторная работа № 4 Обобщенное программирование. Использование стандартной библиотеки Java Костюк А.А, Амзаев А.А., Дорошенко А.В. – 1-5М Цель работы: получить навыки в обобщенном программировании и использовании стандартной библиотеки Java. Ход работы: Обобщённое программирование – парадигма программирования, заключающаяся в таком описании данных и алгоритмов, которое можно применять к различным типам данных, не меняя само это описание. В том или ином виде поддерживается разными языками программирования. Возможности обобщённого программирования впервые появились в виде дженериков (обобщённых функций) в 1970-х годах в языках Клу и Ада, затем в виде параметрического полиморфизма в ML и его потомках, а затем во многих объектно-ориентированных языках, таких как C++, Java, Object Pascal, D, Eiffel, языках для платформы .NET и других. C выходом версии J2SE 5.0, Java стал поддерживать обобщенные типы (generics (дженерики)), а также создание обобщенных методов. Обобщенный тип объявляет параметры типа (type parameters) – плейсхолдеры типов, которые будут заполнены в дальнейшем при использовании обобщенного типа, путем передачи в него аргументов типа (type arguments). class Account<T> { private T id; private int sum; Account(T id, int sum) { this.id = id; this.sum = sum; } public T getId() { return id; } public int getSum() { return sum; } public void setSum(int sum) { this.sum = sum; } } С помощью буквы T в определении класса class Account <T> мы указываем, что данный тип T будет использоваться этим классом. Параметр T 15 в угловых скобках называется универсальным параметром, так как вместо него можно подставить любой тип. При этом пока мы не знаем, какой именно это будет тип: String, int или какой-то другой. Причем буква T выбрана условна, это может и любая другая буква или набор символов. У Java есть стандартная библиотека – пакет java.util, который содержит в себе: ‒ коллекции; ‒ дженерики; ‒ множество классов. Java включает большое количество вспомогательных классов, широко используемых в других встроенных пакетах Java. Эти классы расположены в пакете java.util и используются для работы с набором объектов, взаимодействия с системными функциями низкого уровня, для работы с математическими функциями, генерации случайных чисел и манипуляций с датой и временем. Класс Date Класс Calendar Интерфейс Collection Пакет java.util Имеет два конструктора : первый не имеет параметров и присваивает объекту текущую дату и время, второй устанавливает их с помощью задания в параметре количества миллисекунд, прошедших с 1.1.70. Имеет основные методы after, before, clone, getTime и setTime. Абстрактный, не содержит конструкторов. Существует конкретная реализация этого класса GregorianCalendar. Класс включает множество констант, содержащих текущую дату и время (DAY, HOUR и др.), названия месяцев (в английской аббревиатуре). Является основой всей иерархии классов-коллекций и определяет базовую функциональность любой коллекции - набор методов, которые позволяют добавлять, удалять, 16 Интерфейс Set Интерфейс List Класс Properties выбирать элементы коллекции. Классы, которые имплементируют интерфейс Collection, могут содержать дубликаты и пустые (null) значения. AbstractCollection, являясь абстрактным классом обеспечивает, служит основой для создания конкретных классов коллекций и содержит реализацию некоторых методов, определенных в интерфейсе Collection. Расширяет интерфейс Collection. Классы, которые реализуют этот интерфейс не разрешают наличие дубликатов. В коллекции этого типа допускается наличие только одной ссылки типа null. Любой объект добавляемый в Set должен реализовать метод equals для того, чтобы его можно было сравнить с другими. AbstractSet являясь абстрактным классом представляет из себя основу для реализации различных вариантов интерфейса Set. Расширяет интерфейс Collection. Классы, которые реализуют этот интерфейс содержат упорядоченную последовательность объектов (Объекты хранятся в том порядке, в котором они были добавлены). List обеспечивает также ListIterator, который позволяет перемещаться как вперед, так и назад, по элементам списка. AbstractList являясь абстрактным классом представляет из себя основу для реализации различных вариантов интерфейса List. Предназначен для хранения набора свойств (параметров). Методы String getProperty(String key), String getProperty(String key, String defaultValue) позволяют получить 17 Класс Arrays Класс StringTokenizer свойство из набора. С помощью метода setProperty(String key, String value) это свойство можно установить. Является статическим и обеспечивает набор методов для выполнения таких операций над массивами, как поиск, сортировка, сравнение. В Arrays так же определен статический метод public List aList(a[] data); который возвращает список фиксированного размера основанный на массиве. Изменения в List можно внести изменив данные в массиве. Обратная операция, т.е. представление какой-либо коллекции в виде массива осуществляется с помощью статического метода Object[] toArray() определенного в классе Collections. Предназначен для разбора строки по лексемам (tokens). Строка, которую необходимо разобрать, передается конструктору StringTokenizer(String str) в качестве параметра. Определено еще два перегруженных конструктора, которым дополнительно можно передать строку-разделитель лексем StringTokenizer(String str, String delim) и признак возврата разделителя лексем StringTokenizer(String str, String delim, Boolean retirnDelims). Разделителем лексем по умолчанию служит пробел. И множество других. Вывод: в процессе выполнения лабораторной работы были получены навыки в обобщенном программировании и использовании стандартной библиотеки Java. 18 Лабораторная работа № 5 Алгоритмические средства языка Java Костюк А.А, Амзаев А.А, Дорошенко А.В Цель работы: получить навыки в алгоритмических средствах языка Java. Ход работы: Алгоритм представляет собой последовательность шагов, которая призвана решить определенную задачу. Иными словами алгоритм – это способ решения этой задачи. В этом качестве алгоритм применяется для обозначения метода решения любых, в том числе и повседневных задач. Но в данном случае речь будет идти об алгоритмах компьютерных вычислений. Сам термин "алгоритм" произошел от имени персидского математика Аль-Хорезми, труды которого сыграли важную роль на становление математики как науки. Алгоритм может иметь входные данные, над которыми производятся вычисления, а также может иметь выходной результат - одно значение или набор значений. По сути, задача алгоритма состоит в преобразовании входных значений в выходные. Важным критерием алгоритма выступает эффективность. Алгоритм может прекрасно решать поставленную задачу, но при этом быть не эффективным. Как правило, под эффективностью алгоритма подразумевается время, за которое должен выполняться данный алгоритм. Общее время выполнения программы зависит от двух факторов: ‒ времени выполнения каждого оператора ‒ частоты выполнения каждого оператора Время выполнение каждого оператора зависит от среды выполнения, операционной системы и других системных характеристик. 19 Суть основного алгоритма приложения заключается в создании необходимых платформ, регулировке скорости и перемещения шарика по поверхности с учетом поведения камеры. Приведем пример алгоритма быстрой сортировки на Java. Код программы: import java.util.Arrays; public class QuickSort { public static void quickSort(int[] array, int low, int high) { if (array.length == 0) return;//завершить выполнение если длина массива равна 0 if (low >= high) return;//завершить выполнение если уже нечего делить // выбрать опорный элемент int middle = low + (high - low) / 2; int opora = array[middle]; // разделить на подмассивы, который больше и меньше опорного элемента int i = low, j = high; while (i <= j) { while (array[i] < opora) { i++; } while (array[j] > opora) { j--; } if (i <= j) {//меняем местами int temp = array[i]; array[i] = array[j]; array[j] = temp; i++; j--; } } // вызов рекурсии для сортировки левой и правой части if (low < j) quickSort(array, low, j); if (high > i) quickSort(array, i, high); } public static void main(String[] args) { int[] x = { 8, 0, 4, 7, 3, 7, 10, 12, -3 }; System.out.println("Было"); System.out.println(Arrays.toString(x)); int low = 0; int high = x.length - 1; quickSort(x, low, high); 20 System.out.println("Стало"); System.out.println(Arrays.toString(x)); } } Вывод: в процессе выполнения лабораторной работы были получены навыки в алгоритмических средствах языка Java. 21 Лабораторная работа № 6 Использование стандартной библиотеки Kotlin Костюк А.А., Амзаев А.А., Дорошенко А.В. Цель работы: получить навыки в использовании стандартной библиотеки Kotlin. Ход работы: Kotlin – статически типизированный язык программирования, работающий поверх JVM и разрабатываемый компанией JetBrains. Также компилируется в JavaScript, и в исполняемый код ряда платформ через инфраструктуру LLVM. Язык назван в честь острова Котлин в Финском заливе, на котором расположен город Кронштадт. Авторы ставили целью создать язык более лаконичный и типобезопасный, чем Java, и более простой, чем Scala. Следствием упрощения по сравнению со Scala стали также более быстрая компиляция и лучшая поддержка языка в IDE. Язык полностью совместим с Java, что позволяет javaразработчикам постепенно перейти к его использованию; в частности, в Android язык встраивается с помощью Gradle, что позволяет для существующего android-приложения внедрять новые функции на Kotlin без переписывания приложения целиком. В Kotlin все является объектом, наверное, разве что кроме циклов (это же не Smalltalk в котором ВСЕ объект). Рассмотрим основную библиотеку, которая автоматически подключается при написании нового программного кода. Ключевые возможности: ‒ Полная совместимость с Java в обе стороны (код на Java и Kotlin можно безболезненно смешивать в одном проекте); ‒ Автоматический вывод типов переменных и функций; 22 ‒ Анонимные функции (лямбда-выражения) позволяют писать более компактный код; ‒ Внешние функции позволяют расширять интерфейс существующих классов, не меняя их; Стандартные библиотеки Kotlin используют стандартные Java библиотеки и так же дополняют их. Пример кода на языке Java и Kotlin для сравнения синтаксиса: Java код: public class Address { private String street; private int streetNumber; private String postCode; private String city; private Country country; public Address(String street, int streetNumber, String postCode, String city, Country country) { this.street = street; this.streetNumber = streetNumber; this.postCode = postCode; this.city = city; this.country = country; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address)o; if (streetNumber != address.streetNumber) return false; if (!street.equals(address.street)) return false; if (!postCode.equals(address.postCode)) return false; if (!city.equals(address.city)) return false; return country == address.country; } @Override public int hashCode() { int result = street.hashCode(); result = 31 * result + streetNumber; result = 31 * result + postCode.hashCode(); result = 31 * result + city.hashCode(); result = 31 * result + (country != null ? country.hashCode() : 0); return result; } @Override public String toString() { return "Address{" + "street='" + street + '\'' + ", streetNumber=" + streetNumber + ", postCode='" + postCode + '\'' + ", city='" + city + '\'' + ", country=" + country + 23 '}'; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public int getStreetNumber() { return streetNumber; } public void setStreetNumber(int streetNumber) { this.streetNumber = streetNumber; } public String getPostCode() { return postCode; } public void setPostCode(String postCode) { this.postCode = postCode; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Country getCountry() { return country; } public void setCountry(Country country) { this.country = country; } } Kotlin код: data class Address(var var var var var street:String, streetNumber:Int, postCode:String, city:String, country:Country) Вывод: в процессе выполнения лабораторной работы были получены навыки в работе со стандартной библиотекой Kotlin. 24 Лабораторная работа № 7 Программирование распределенных приложений Костюк А.А., Амзаев А.А., Дорошенко А.В. Цель работы: получить навыки в программировании распределенных приложений. Ход работы: Развитие современной вычислительной аппаратуры характеризуется четко выраженной тенденцией распространения многопроцессорных компьютеров и вычислительных сетей как локальных, так и глобальных. Уже недалеко то время, когда даже персональные компьютеры будут иметь несколько процессоров, а самые мощные из них могут даже иметь сетевую архитектуру. Поэтому в области программного обеспечения вызывают все больший интерес языки и другие инструментальные средства, поддерживающие разработку распределенных программ. При этом можно выделить три уровня распределенного программирования: ‒ распределенное программирование в малом; ‒ распределенное программирование в большом; ‒ распределенные прикладные программные системы. Распределенное программирование в малом связано с параллельным выполнением операторов одной программы (например, параллельным выполнением циклов). Технология разработки распределенных программ связана с реализацией коммуникационных пакетов, а также языков программирования и библиотек, облегчающих использование таких пакетов. Примерами коммуникационных пакетов могут служить такие широко используемые пакеты как PVM и MPI. Из языков, опирающихся на эти пакеты следует выделить прежде всего HPF/2 (High Performance Fortran, version 2) и 25 язык, разработанный в ИСП РАН, - mpC. Среди многочисленных библиотек наиболее интересны различные алгебраические библиотеки (например, ScalaPack), а также библиотеки, вводящие параллельные конструкции в стандартные языки программирования (одна из таких библиотек DPJ - Data Parallel Java - разрабатывается в ИСП РАН). Распределенное программирование в большом состоит в разработке распределенных программных систем. В последнее время широко используются объектно-ориентированные технологии разработки таких систем. Наиболее известные такие технологии связаны с системой стандартов OMG (стандарт CORBA). Распределенные прикладные программные системы предназначены для поддержки коллективных разработок и других видов коллективной деятельности в самых различных областях. В таких системах используются новейшие достижения в области вычислительной техники и коммуникаций. Примером такой системы может служить система POLITeam (GMD-FIT, Германия), основной целью которой является обеспечение оперативной работы правительства Германии, расположенного в двух городах - Берлине и Бонне, в настоящее время имеются в наличии как аппаратные, так и программные средства, позволившие реализовать и успешно эксплуатировать такую систему. С проектом POLITeam связано одно из ведущих научных направлений GMD - "Системы поддержки совместных разработок на основе коммуникации" (Communication and Cooperation Systems). Это одно из интенсивно развивающихся научно-исследовательских и прикладных направлений современной информатики. Широко известны такие системы для организации совместной работы как система Totem, разработанная в Университете г. Санта-Барбара, Калифорния, США, система Transis, разработанная в Университете г. Иерусалима, Израиль, система Horus Корнельского Университета (США) и многие другие. При разработке и реализации перечисленных систем применялись различные подходы, что 26 позволяет разработать их аналитический обзор с целью выбора наиболее дешевого и приемлемого подхода. Это относится и к инструментальным программным средствам, используемым для реализации систем поддержки совместных разработок. Одним из широко известных инструментальных средств, используемых при разработке и реализации таких систем, является пакет Rampart Toolkit, разработанный в AT&T Bell Laboratories, Нью-Джерси, США. Для реализации системы поддержки совместных разработок в рамках проекта POLITeam использовалась другая не менее известная инструментальная система LinkWorks фирмы Digital Equipment Corporation, США. Вывод: в процессе выполнения лабораторной работы были получены навыки в программировании распределенных приложений. 27 Лабораторная работа № 8 Технология коллективной разработки Java-приложений Костюк А.А., Амзаев А.А., Дорошенко А.В. Цель работы: получить навыки в работе с технологией коллективной разработки Java-приложений. Ход работы: Одним из основных вопросов коллективной разработки является разделение труда – от равноправных соисполнителей до организации в виде жесткой иерархии (например, бригады главного программиста). Основные члены бригады выполняют функции, перечисленные ниже: ‒ Главный программист. Лично выполняет анализ и проектирование, создание и отладку кода, написание документации. Должен обладать талантом, большим опытом работы и существенными знаниями. ‒ Дублер. Может выполнять любую работу главного программиста, но менее опытен. Подстраховывает главного программиста, может заниматься написанием кода, но не несет ответственности за проект. ‒ Администратор, он же - менеджер. Под его контролем - деньги, люди, помещения, машинные ресурсы, контакты с другими группами и руководством. ‒ Редактор. Фактически, это технический писатель. Его задача критически переработать черновики документации (созданные главным программистом), снабдить их ссылками и библиографией и обеспечить публикацию или помещение в Интернете. ‒ Языковед. Эксперт в тонкостях языков программирования. Может найти эффективные способы использования языка для решения сложных задач. Обычно работает с несколькими бригадами. ‒ Инструментальщик. Разработчик специализированных инструментов утилит и скриптов. Поддерживает основной инструментарий и 28 оказывает по нему консультации. При необходимости может осуществлять администрирование операционной системы. ‒ Отладчик. Разработчик тестов и организатор тестирования программного продукта. ‒ Делопроизводитель. Отвечает за регистрацию всех технических данных бригады в библиотеке делопроизводителю, рутинных работ. делопроизводителя программного активные Заметим, продукта. программисты что в автоматизированы освобождались настоящее и Благодаря время переданы от функции репозиторию проекта. Известно, что первые коллективные разработки программ велись примерно так. Начальник выполнял разделение большого проекта на меньшие части и передавал далее по иерархии. Через некоторое время, теперь уже снизу вверх, шла сборка программы из написанных фрагментов. Собрать работающий программный продукт удавалось не всегда. Когда над проектом начинает работать более одного человека, появляется проблема обмена изменениями в проекте. Множество сложностей коллективной разработки решают системы контроля версий. По статистике, лучшим, на данный момент, себя показывает Git. Git — это бесплатная система контроля версий с открытым исходным кодом, которая позволяет легко отслеживать изменения в проектах и облегчает взаимодействие между разработчиками, дизайнерами и другими участниками разработки. Её используют более 69% компаний в индустрии, а недавние улучшения в Git заставляет всё больше студий разработчиков игр переходить на неё с Perforce и Subversion. 29 Результат работы программы: Основной код программы: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Calculator { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { CalculatorFrame frame = new CalculatorFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } class CalculatorFrame extends JFrame { public CalculatorFrame() { setTitle("Calculator"); CalculatorPanel panel = new CalculatorPanel(); add(panel); pack(); } } class CalculatorPanel extends JPanel { public CalculatorPanel() { setLayout(new BorderLayout()); result = 0; lastCommand = "="; start = true; display = new JButton("0"); display.setEnabled(false); add(display, BorderLayout.NORTH); ActionListener insert = new InsertAction(); ActionListener command = new CommandAction(); panel = new JPanel(); panel.setLayout(new GridLayout(4, 4)); addButton("7", insert); addButton("8", insert); 30 addButton("9", insert); addButton("/", command); addButton("4", addButton("5", addButton("6", addButton("*", insert); insert); insert); command); addButton("1", addButton("2", addButton("3", addButton("-", insert); insert); insert); command); addButton("0", addButton(".", addButton("=", addButton("+", insert); insert); command); command); add(panel, BorderLayout.CENTER); } private void addButton(String label, ActionListener listener) { JButton button = new JButton(label); button.addActionListener(listener); panel.add(button); } private class InsertAction implements ActionListener { public void actionPerformed(ActionEvent event) { String input = event.getActionCommand(); if (start) { display.setText(""); start = false; } display.setText(display.getText() + input); } } private class CommandAction implements ActionListener { public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); if (start) { if (command.equals("-")) { display.setText(command); start = false; } else lastCommand = command; } else { calculate(Double.parseDouble(display.getText())); lastCommand = command; start = true; } } } public void calculate(double x) { if (lastCommand.equals("+")) result += x; else if (lastCommand.equals("-")) result -= x; else if (lastCommand.equals("*")) result *= x; else if (lastCommand.equals("/")) result /= x; else if (lastCommand.equals("=")) result = x; display.setText("" + result); } 31 private private private private private JButton display; JPanel panel; double result; String lastCommand; boolean start; } Вывод: в процессе выполнения лабораторной работы были получены навыки в работе с технологией коллективной разработки Java-приложений. 32