Практические задания по курсу объектно-ориентированного программирования.

учебный год. Семестр II.

Комбинированное задание №1:

1.  см. http://ccfit. *****/~ddol//oop-2-course/Seminar1-NSU. doc (пункты 4.1 – 4.8),

2.  см. http://ccfit. *****/~ddol//oop-2-course/Seminar2-NSU. doc (пункты 5.1 – 5.2).

Задание №2: Простой контейнер для хранения объектов типа java. lang. Object.

1.  Структура программы:

/ru/nsu/phf/phti/container – пакет, содержащий класс контейнера и вспомогательные классы. /ru/nsu/phf/phti/container/test – пакет, содержащий тестовые классы для тестирования класса контейнера.

2.  Контейнер должен хранить элементы типа java. lang. Object в односвязном списке и предоставлять следующие возможности:

a.  Добавление элемента в начало списка.

b.  Добавление, удаление, получение элемента по номеру позиции.

c.  Поиск элемента в списке. При поиске должно использоваться сравнение объектов с помощью переопределенного метода boolean equals(Object obj) из класса java. lang. Object, а не через оператор ==.

d.  Распечатка на экран всех элементов контейнера и их общего кол-ва (используя переопределенный метод toString()).

3.  Тестовый пакет должен содержать тестовый класс Point, содержащий поля типа int (координаты x и y). Два объекта Point считаются одинаковыми, только если их координаты совпадают. Кроме того необходимо написать тестовый класс (Test), который:

a.  Создает объекты класса Point со случайными координатами от 0 до 2. Используйте метод random() из класса java. lang. Math. для получения случайного чиса. Кол-во создаваемых объектов задается в public static final поле класса Test.

НЕ нашли? Не то? Что вы ищете?

b.  Сохраняет созданные объекты в контейнере и распечатывает содержимое контейнера.

c.  Пробегается по контейнеру и удаляет повторяющиеся объекты (см. описание одинаковых элементов класса Point). Т. о. после фильтрации список должен содержать только точки (объекты класса Point) с разными координатами.

d.  Распечатывает новое состояние контейнера.

4.  Необходимо использовать следующие техники:

a.  Не создавать открытых (public) членов класса. Где это необходимо, использовать accessor-методы (getters & setters). Стараться как можно прочнее закрыть состояние класса от внешних воздействий. Пример getters & setters:

// setter

void setMember (int member) {

this. member = member;

}

// getter

int getMember() {

return member;

}

b.  Корректно переопределить метод boolean equals(Object obj) в классе Point. Объяснить, почему при переопределении метода equals() необходимо всегда переопределять еще и метод hashCode().

c.  Использовать метод toString() для распечатывания состояния точки/контейнера (point. toString(), container. toString()).

Дополнительные подзадания (для тех, кто желает получить оценки “4” и “5”):

1.  Реализовать контейнер на основе динамического массива.

2.  Реализовать в классе Point интерфейс java. parable. Добавить в класс контейнера метод sort() для сортировки элементов.

Задание №3: Тестирование стандартных контейнеров.

1.  Структура программы:

a.  /ru/nsu/phf/phti/collections – пакет, содержащий классы и. properties-файлы программы.

b.  /ru/nsu/phf/phti/collections/tests – пакет, содержащий тестовые классы для тестирования работы контейнеров.

2.  Конфигурационный файл /ru/nsu/phf/phti/collections/collections. properties содержит набор свойств[1] <CollectionLabel>=<CollectionClassName>, которые задают подлежащие тестированию контейнеры. Здесь <CollectionLabel> – это метка (условное имя тестируемого контейнера), а <CollectionClassName> – полное имя класса контейнера. Пример:

MySet=java. util. HashSet

MyList=java. util. ArrayList

3.  Конфигурационный файл /ru/nsu/phf/phti/collections/actions. properties содержит набор свойств <TestLabel>=<TestClassName>, которые перечисляют все возможные тесты. Здесь <TestLabel> – это метка теста, а <TestClassName> – полное имя класса теста над контейнером. Пример:

add=ru. nsu. phf. phti. collections. tests. AddTest

get=ru. nsu. phf. phti. collections. tests. GetTest

iterator=ru. nsu. phf. phti. collections. tests. IteratorTest

search=ru. nsu. phf. phti. collections. tests. SearchTest

sort=ru. nsu. phf. phti. collections. tests. SortTest

4.  Программа запускается следующим образом:

java ru. nsu. phf. phti. collections. TestCollection <CollectionLabel> <TestLabel> <NumberOfObjects>

где <CollectionLabel> – метка контейнера из файла collections. properties, <TestLabel> – метка теста из файла actions. properties (либо предопределенная метка all – для прогона всех тестов), <NumberOfObjects> – количество объектов для тестирования. Примеры:

java ru. nsu. phf. phti. collections. TestCollection MySet add 10000

java ru. nsu. phf. phti. collections. TestCollection MySet all 10000

java ru. nsu. phf. phti. collections. TestCollection add 10000

java ru. nsu. phf. phti. collections. TestCollection all 10000

В результате программа выполняет выбранный тест с помощью <NumberOfObjects> объектов типа java. lang. Integer (объекты инициализируются с помощью java. lang. Math. random()) и выдает результат на экран. Если в качестве имени теста указано all, то выполняются все зарегистрированные тесты. Если имя контейнера не указано, то тестируются все зарегистрированные контейнеры. Если какой-либо тест не применим к данному контейнеру, то выводится соответствующая информация на экран (при этом, если надо выполнить еще несколько тестов, работа программы не прекращается).

Во время запуска программы имена классов тестов и контейнеров считываются из. properties-файлов. В дальнейшем программа может создавать объекты определенного контейнера или теста используя только текстовое имя класса.

Все классы тестов должны реализовывать интерфейс CollectionTest, который содержит все необходимые методы для выполнения теста. Например:

interface CollectionTest {

public void processTest(List container, int numberOfObjects)

throws UnsupportedTestException;

public void processTest(Set container, int numberOfObjects)

throws UnsupportedTestException;

public void processTest(Map container, int numberOfObjects)

throws UnsupportedTestException;

}

Соответственно, основная программа работает с инстанциированным объектом через интефрейс. Исключение UnsupportedTestException выбрасывается в том случае, когда тест не может быть применен к данному типу контейнера. Например, тест insert невозможно применить к java. util. HashSet.

5.  Список необходимых тестов, которые программа должна уметь выполнять:

Тест

Описание

add

Измерение скорости последовательного добавления <NumberOfObjects> элементов в контейнер, созданный при помощи конструктора по умолчанию. Для java. util. List и java. util. Set используется метод add(Object obj). Для java. util. Map используется метод put(Object key, Object value) (значения key и value – одинаковые).

get

Измерение скорости извлечения <NumberOfObjects> элементов из заполненного[2] контейнера (элементы выбираются случайным образом). Для java. util. List используется извлечение по номеру позиции. Для остальных контейнеров – не работает.

search

Измерение скорости поиска <NumberOfObjects> элементов в заполненном контейнере (элементы выбираются случайным образом). Для java. util. List и java. util. Set используется метод contains(), для java. util. Map используется метод get().

sort

Измерение скорости сортировки элементов в заполненном контейнере. Только для java. util. List.

insert

Измерение скорости вставки <NumberOfObjects> элементов в контейнер, созданный при помощи конструктора по умолчанию (каждый раз новый элемент добавляется в позицию со случайным номером). Только для java. util. List.

iterator

Измерение скорости итерации элементов в заполненном контейнере (достаточно просто “пробежаться” по всем элементам). Для итерации используется объект типа java. util. Iterator. Только для java. util. Set и java. util. List.

remove

Измерение скорости удаления <NumberOfObjects>/2 элементов из заполненного контейнера (элементы удаляются случайным образом).

6.  Для проведения тестов необходимо использовать как минимум 2 реализации java. util. List и по одной реализации java. util. Map и java. util. Set (см. документацию по пакету java. util).

7.  Необходимо использовать следующие техники:

a.  Для загрузки содержимого. properties-файлов использовать метод java. lang. Class. getResourceAsStream(). Для работы с содержимым. properties-файлов использовать класс java. util. Properties().

b.  Создавать (инстанциировать) объекты тестов и контейнеров с помощью вызова Class. forName("...").newInstance().

c.  Обрабатывать все исключения, которые описаны в методах классов из Java API. Не позволять программе “вываливаться”. В случае отлова исключения распечатывать его текстовое сообщение и трассировочный путь (см. описания методов getMessage() и printStackTrace() класса java. lang. Throwable).

d.  Выводить “usage message” при вводе неправильных параметров с командной строки.

e.  Использовать интерфейсы java. util. Map, java. util. Set и java. util. List при работе с инстанциированными объектами контейнеров.

Дополнительные подзадания (для тех, кто желает получить оценки “4” и “5”):

1.  Полностью задокументировать один из классов по правилам Javadoc.

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

Задание №4: Игра “Сапер”.

1.  Напишите аналог игры “Сапер” (“Minesweeper”), которая входит в набор стандартных программ, поставляемых вместе с Windows OS. Используйте библиотеку Swing для разработки графического интерфейса.

2.  Программа должна обеспечивать следующие возможности:

a.  Размер игрового поля – 9x9, количество мин на игровом поле – 10.

b.  Игра в любой момент может быть начата с начала, если нажата “специальная” кнопка.

c.  Главное окно программы содержит часы-таймер, которые показывают время (в секундах), потраченное на решение задачи. Время начинает идти, когда происходит первое нажатие на клетку поля. Время останавливается, когда игра окончена. Значение таймера сбрасывается, если нажата “специальная” кнопка.

d.  При нажатии правой кнопки мышки над ячейкой игрового поля, эта ячейка помечается флажком (если в этой ячейке флажок уже установлен, то он сбрасывается). Для изображения флажка рекомендуется использовать картинку.

e.  При нажатии левой кнопки мышки над ячейкой игрового поля, эта ячейка открывается и в ней показывается число близлежащих мин (для разных чисел используются разные цвета). Если число близлежащих мин равно 0, то в открытой ячейке ничего не отображается (в этом случае запускается алгоритм, открывающий вокруг нее все ячейки до тех пор, пока не будет найдена граница, состоящая из ячеек, у которых число близлежащих мин > 0)[3]. Если в этой ячейке находилась мина, то необходимо – a) с помощью всплывающего меню сообщить, что игра окончена с результатом “неуспех”, b) пометить на игровом поле все ячейки, в которых находились мины (чтобы игрок мог посмотреть, в каком месте он ошибся), c) заблокировать игровое поле таким образом, чтобы игрок больше не мог открывать ячейки или помечать их флажками. Сброс игры происходит только после нажатия на “специальную” кнопку.

f.  Главное окно программы содержит счетчик обнаруженных мин (т. е. ячеек, помеченных флажком). Игра заканчивается, когда на игровом поле остаются только 10 неоткрытых ячеек (ровно столько, сколько было мин). В этом случае необходимо – a) с помощью всплывающего меню сообщить, что игра окончена с результатом “успех”, b) пометить на игровом поле флажками все ячейки, в которых находились мины, c) заблокировать игровое поле таким образом, чтобы игрок больше не мог открывать ячейки или помечать их флажками. Сброс игры происходит только после нажатия на “специальную” кнопку.

g.  Главное окно программы должно корректно обрабатывать такие события, как изменение размера и закрытие окна.

3.  Используйте следующие техники при написании программы:

·  Часы-таймер должны быть реализованы отдельным потоком. Используйте методы sleep(), wait() и notifyAll() определенные в классе java. lang. Object.

·  Для определения типа нажатой кнопки используйте методы класса javax. swing. SwingUtilities.

Дополнительные подзадания (для тех, кто желает получить оценки “4” и “5”):

1.  Добавьте в игру поддержку “highscore”. Разработайте интерфейс для его показа. Используйте файл для хранения “highscore”.

2.  Адаптируйте вашу программу так, чтобы превратить ее в апплет (при этом у вас должна сохраниться копия оригинального кода программы, где она запускается как обычное Java-приложение). Используйте тег <APPLET> или <OBJECT> для встраивания апплета в HTML-страницу.

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

Внимание: варианты 1 и 2 могут быть несовместимыми.

Задание №5: Эмулятор фабрики по производству машин.

1.  Напишите приложение, моделирующее работу фабрики по сборке автомобилей. Используйте библиотеку Swing для разработки графического интерфейса.

2.  При запуске приложение открывает графическое окно, в котором пользователь может контролировать основные параметры работы фабрики (см. дальше).

3.  Автомобиль представляет собой объект, состоящий из трех типов деталей: корпуса, двигателя и “запчастей”. Для того чтобы собрать 1 автомобиль, необходимо использовать 1 корпус, 1 двигатель и 2 “запчасти”. Каждая из этих деталей (в том числе и сам автомобиль) должна быть представлена соответствующим Java-классом, унаследованным от абстрактного класса Widget. В классе Widget необходимо предусмотреть общие для всех деталей [accessor-]методы и атрибуты (например, уникальный идентификатор, дату производства, наименование модели детали и т. п.), а в классе детали – только специфичные именно для данной детали (например, цвет для корпуса, рабочий объем в кубических сантиметрах для двигателя и т. д.). Каждый объект детали должен предоставлять о себе полную информацию с помощью переопределенного метода toString(). Объект-автомобиль должен содержать в себе все объекты-детали, из которых он был собран.

4.  Процесс работы фабрики показан на следующем рисунке:

5.  Все склады имеют определенный размер, который нельзя превышать. Размеры складов, количество рабочих (workers) и продавцов (dealers) задается в конфигурационном файле. Пользователь в любой момент времени должен видеть в графическом окне приложения a) количество деталей на всех складах (включая автомобили на складе готовых изделий), b) количество деталей, произведенных каждым из поставщиков за все время работы программы, c) количество произведенных автомобилей и d) количество проданных автомобилей.

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

7.  Каждый продавец, запрашивает со склада готовой продукции 1 автомобиль в несколько секунд. Количество секунд для всех продавцов одним параметром задается в конфигурационном файле и во время работы программы может изменяться единым на всех ползунком. Информация о проданном автомобиле должна записываться в лог-файл программы. Эта информация должна содержать дату продажи и параметры автомобиля (которые можно получить через toString()).

8.  Поток «контроллер склада готовых изделий» просыпается при любой отправке автомобиля со склада готовой продукции. Он анализирует состояние склада и, в случае необходимости, передает запрос на изготовление новых автомобилей на фабрику. При запуске программы «контроллер» получает из конфигурационного файла параметр, который определяет, насколько надо заполнить склад готовых изделий при старте (от 10% до 100%) и передает соответствующий запрос на фабрику.

9.  Рабочий запрашивает со складов необходимые ему детали и собирает из них автомобиль. Если на складе нет нужной детали, то рабочий ждет поставки. Собранный автомобиль помещается на склад готовых изделий. Если на складе готовых изделий нет свободного места – рабочий «засыпает», пока место не освободится.

10.  Необходимо использовать следующие техники:

·  Для синхрониазции потоков использовать методы wait() и notifyAll() класса java. lang. Object. Объяснить, почему не рекомендуется использовать метод notify().

·  Логирование информации о работе фабрики должно осуществляется через класс java. util. logging. Logger.

·  Для наглядности сделайте так, чтобы поставщики создавали детали с изменяющимися параметрами. Например, чтобы для каждого нового корпуса его цвет выбирался бы случайным образом из списка доступных значений (красный, желтый, синий, заленый и т. д.).

Дополнительные подзадания (для тех, кто желает получить оценки “4” и “5”):

1.  Реализуйте на фабрике пул потоков. Сделайте так, чтобы при запуске приложения у вас сразу создавалось бы по одному потоку на одного рабочего. Когда на фабрику поступает новый запрос, из пула берется поток-рабочий и запускается на сборку нового автомобиля. После того, как сборка автомобиля завершена, поток возвращается обратно в пул. Если в пуле нет потоков (все потоки забраны из пула и в настоящее время работают), то сборка нового автомобиля не начинается до тех пор, пока один из потоков не вернется обратно в пул.

Объясните целесообразность использования пула потоков по сравнению с созданием нового потока «при необходимости».

2.  Заведите для класса Widget специальный параметр «срок годности». Срок годности для каждой детали задается поставщиком при ее создании, для автомобиля – собравшим его рабочим. Срок годности автомобиля не должен превышать срок годности любой из его деталей. Если у детали (корпуса, двигателя или «запчасти») к моменту получения ее со склада срок годности закончился (т. е. «дата производства» + «срок годности» > «текущее время»), то ее нельзя использовать. Такую деталь можно выбросить, а вместо нее взять более новую. Если у автомобиля, находящегося на складе готовых изделий срок годности закончился, то этот автомобиль не подлежит продаже. Такой автомобиль должен быть возвращен на фабрику, где детали с истекшим сроком годности должны быть заменены на более новые.

Задание №6:

Задание отменено.

Примечание: Оценка заданий.

    Комбинированное задание 1 оценивается по шкале “сдал” / “не сдал”. Задания 2-5 оцениваются по 5-тибальной шкале (“не сдал” / 3-4-5). Оценка задания зависит от следующих факторов:

o  Точно[4] и в необходимом объеме выполненное основное задание;

o  Понимание принципов/технологий/механизмов, использованных при написании кода;

o  Понимание кода сдаваемого задания “вдоль и поперек”, умение ответить на вопрос “а почему сделано именно так?”;

o  Хороший стиль написания кода[5]: модульность (разбивка на интерфейсы, классы, пакеты), форматирование, именование классов, методов, атрибутов, переменных, и т. д. и т. п. (оценивается достаточно субъективно);

o  Умение при необходимости “на месте” исправить найденные недостатки или добавить недостающие “фичи” и продемонстрировать работу исправленной программы.

o  Для оценки “4” – выполненное хотя бы одно дополнительное подзадание, для оценки “5” – два подзадания.

    В случае дифференцированного зачета оценка за работу в семестре будет выставляться по следующей формуле:

    В случае недифференцированного зачета, “зачет” ставится только в том случае, если Оценка >= 3.

[1] Свойство (англ. property) – это пара текстовых значений вида <key>=<value>.

[2] Здесь и далее считается, что заполненный контейнер заведомо содержит <NumberOfObjects> элементов.

[3] Для справки – см. как это работает в “Сапере”.

[4] Тем не менее, возможно, что описание определенных заданий может оказаться недостаточно подбробным или допускающим в некоторых пределах вольную трактовку. В этом случае студенту необходимо обратиться к преподавателю для получения более точной постановки задания.

[5] См. http://ccfit. *****/~ddol//oop-2-course/CodeConventions. pdf.