Объектно-ориентированное программирование

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    123,43 Кб
  • Опубликовано:
    2014-03-21
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Объектно-ориентированное программирование

Министерство общего и профессионального образования

Российской Федерации

Казанский государственный технический университет

имени. А.Н. Туполева

Кафедра КС






Курсовая работа

по дисциплине «Объектно-ориентированное программирование»


Исполнитель: студент группы 4201 Д.А. Павлов

Руководитель: доц. кафедры АСОИУ В.И. Медведев









Казань 2010

Содержание

1. Задание

. Уточнение задания

. Описание разрабатываемой программы с точки зрения пользователя

. Описание разрабатываемой программы с точки зрения программиста

.1 Объектное представление программы

.2 События

.3 Потоки

. Поэтапная разработка программной системы

.1 Этап 1. Разработка класса корабля

.2 Этап 2. Разработка класса прикладного окна

.3 Этап 3. Разработка события but

.4 Этап 4. Разработка класса основного окна и графики

.5 Этап 5. Разработка дочерних окон

.6 Этап 6. Разработка специального объекта (заправщик)

. Описание проблем, возникших при разработке программной системы

. Список используемой литературы

Приложение 1. Диаграмма классов разработанной программы

Приложение 2. Текст программы на языке C#

Приложение 3. Текст программы на языке Java

Приложение 4. Текст программы на языке C++/CLI

1. Задание

программа приложение окно

Луна освоена и на ней построены города, идет разработка полезных ископаемых. Между планетами курсируют корабли. Для перемещения от одной планеты к другой сначала надо выйти на орбиту, затем начать двигаться по заданной траектории. Если корабли встречаются, то один из них останавливается, отодвигается в сторону, пропуская другой. К ним подлетает специальный корабль-заправщик с Земли.

2. Уточнение задания

Приложение включает прикладное окно, в котором отображается функционирование объектов, дочернее окно, содержащее интерфейсные элементы, управляющие программой, и дочернее окно, в которое выдается информация о состоянии и поведении объектов (пропускает другой корабль, размер топлива). Корабли перемещаются с помощью своих потоков. Среди интерфейсных элементов есть кнопка и редактор текста, с помощью которых можно добавить топливо. Программу реализовать на языках C#, Java и C++\CLI.

3. Описание разрабатываемой программы с точки зрения пользователя

Программа представлена прикладным и двумя дочерними окнами. В прикладном окне схематично изображены Земля, Луна, их орбиты и движущиеся по своим траекториям корабли. На каждом корабле написан его порядковый номер, над ним - текущее количество топлива.

Первое дочернее окно содержит текстовое поле и кнопки «Добавить корабль», «Добавить топливо», «Пауза». По нажатию на кнопку «Добавить корабль» с Земли запускается очередной корабль и начинает движение по орбите, потом полет к Луне. По нажатию на кнопку «Пауза» все корабли останавливаются, а надпись на кнопке сменяется на «Старт». При повторном нажатии корабли продолжают движение. По нажатию на кнопку «Добавить топливо» кораблю, чей номер задан в текстовом поле, добавляется 20 единиц топлива.

Диаграмма вариантов использования языка UML изображает действия, выполняемые пользователем программы. С точки зрения пользователя приложение предполагает три варианта использования:

запустить новый корабль (start new ship),

приостановить движение кораблей (suspend the ships moving),

возобновить движение кораблей (resume the ships moving),

добавить топливо выбранному кораблю (add fuel to selected ship).

Диаграмма вариантов использования представлена на рис. 3.1.

Рис. 3.1. Диаграмма вариантов использования приложения

. Описание разрабатываемой программы с точки зрения программиста

.1 Объектное представление программы

Программа включает объекты разных типов. Главными объектами программы являются объект прикладного окна класса Program и объекты дочерних окон класса Form или Frame. При создании объекта прикладного окна создаются дочерние окна, 1 объект обычного корабля класса Ship и один объект корабля-заправщика класса Charger. Объект обычного корабля сразу начинает взлет и движение по траектории, а заправщик - движение по орбите Земли против часовой стрелки.

Каждый обычный объект корабля движется в соответствии с потоковой функцией Move() или run() его собственного потока. При изменении координат, объект каждого обычного корабля генерирует событие ev или уведомление, на которое подписан обработчик mainEvent() или функция update() в классе прикладного окна. Параллельно с этим выполняется поток прикладного окна, который отслеживает взаимное положение кораблей и при их встрече «притормаживает» корабль с бОльшим номером.

Первое дочернее окно (Controls) содержит объекты кнопок AddShip, AddFuel и Pause и объект numShip текстового поля. Второе (Info) - массив из десяти текстовых полей, отражающих состояние каждого корабля (не запущен, в полёте, уступает, остановлен, исчез).

.2 События

В программе имеются несколько событий.

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

Также в программе используются предопределённые событие Click, генерируемые при нажатии кнопок. На них реагирует обработчик ButPressed, выбирающий действия в зависимости от текста на кнопке, инициировавшей событие.

.3 Потоки

В программе применяются кроме основного потока, реализуемого функцией Main() или main(), ещё рабочие потоки. Каждый из 10 (максимум) объектов кораблей, а также объект заправщика, располагает собственным потоком с потоковой функцией, причём если функционирование потоковых функций обычных объектов кораблей совпадают - они перемещают объекты кораблей по определенной траектории и отвечают за расход топлива, то потоковая функция объекта заправщика отличается от них.

5. Поэтапная разработка программной системы

Разработка приложения будет осуществляться поэтапно. Вначале разработаем класс Ship потокового объекта и протестируем его. Затем создадим и отладим класс Program потоковых объектов, который управляет кораблями.

В дальнейшем мы наследуем класс Program из базового класса Form или Frame и будем отображать корабли в области клиента прикладного окна (в форме) в виде кругов одного цвета. Нам придётся модифицировать класс Ship потокового объекта, добавив в него координаты и их приращения (вертикальную и горизонтальную скорости). Для обеспечения перерисовки кораблей мы воспользуемся событием или уведомлением, которое будет генерироваться после каждого изменения их координат.

Убедившись в совместном функционировании кораблей и их отображении в области клиента прикладного окна, мы перейдём к разработке дочернего окна, на котором разместим управляющие элементы - кнопки, а затем дочернего окна с текстовыми полями, содержащими информацию о текущем состоянии кораблей.

На последнем этапе мы создадим специальный объект заправщика класса Charger с его потоковой функцией, а в класс Ship обычного объекта корабля добавим переменную, содержащую значение топлива, и функции её изменения.

Для большей наглядности при создании приложений мы воспользуемся диаграммами классов языка UML.

В программе обычные объекты объединим в одномерном массиве длиной num = 10. При необходимости, изменив длину массива, можно создать необходимое количество обычных объектов.

5.1 Этап 1. Разработка класса корабля

На первом этапе создадим основной класс Ship потокового объекта, который включает самые необходимые данные:- номер обычного объекта,- координата по горизонтали,- координата по вертикали,- горизонтальная скорость,- вертикальная скорость,- признак жизни потока (live= true - поток выполняется, live= false - поток завершён),- поток класса Thread.

Включим в класс Ship функции:(int ns) - конструктор класса, ( ) - начать движение обычного объекта,( ) - приостановить выполнение обычного объекта,

Диаграмма класса Ship представлена на рис. 5.3.1.1.

Рис. 5.3.1.1. Диаграмма классов приложения первого этапа разработки

В примере 5.3.1.1 приведена реализация первого этапа на языке C#.

Пример 5.3.1.1. Реализация приложения первого этапа на языке C#.

////////////////////

//C# File Program.csSystem;System.Threading;Ship

{th;id; // Порядковый номер корабляbool live;double x, y; // позицияdouble speedX, speedY; // скорость

// Конструктор класса. Принимает номер корабля.Ship (int ns)

{.id = ns; // Записываем номер корабля.live = false; // первоначально не движемся.x = 160; // начальная позиция по X.y = 300; // начальная позиция по Y.speedX = 0; // скорость движения по горизонтали.speedY = -3; // скорость движения по вертикали (старт с Земли)(); // запускаем движение

}

// функция старта потока движения корабля

public void Start()

{(live == false)

{= true;= new Thread(new ThreadStart(Move)); // Создаем объект-поток "движение корабля"

th.Start(); // Стартуем поток

}

}

// функция остановки потока движения корабля

public void Stop()

{= false;

}

// Поток, отвечающий за движение корабляMove()

{(live) // пока поток жив

{

x += speedX;+= speedY;.WriteLine("Координаты: " + System.Convert.ToString(x) + ", " + System.Convert.ToString(y));.Sleep(60); // спим

}

}

}

//-------------------------------------Program1

{void Main (string[] args)

{Ship1= new Ship (1); // Создать первый обычный объектShip2= new Ship (2); // Создать второй обычный объект.WriteLine ("Объекты функционируют");.Sleep (20); // Объекты функционируют 20 мс.Stop ( ); // Приостановить первый обычный объект.Stop ( ); // Приостановить второй обычный й объект.WriteLine ("Объекты приостановлены и возобновлены");.Start ( ); // Возобновить выполнение первого объекта.Start ( ); // Возобновить выполнение второго объекта.Sleep (20); // Объекты функционируют 20 мс.Stop ( ); // Приостановить первый обычный объект.Stop ( ); // Приостановить второй обычный объект

}

}

.2 Этап 2. Разработка класса прикладного окна

На этом этапе реализуем класс Program, содержащий массив обычных объектов класса Ship и осуществляющий их поочередный запуск, а также приостановку и возобновление функционирования. Дополнительно к указателю ship на массив обычных объектов, класс Program содержит потоковую функцию run(), отслеживающую встречи объектов кораблей. Для её работы в класс Ship добавляется булевская переменная vstrecha, являющаяся индикатором сближения кораблей.

Диаграмма классов Program-приложения второго этапа изображена на рис. 5.3.2.1.


Рис 5.3.2.1. Диаграмма классов Program-приложения второго этапа

Реализация второго этапа разработки Program-приложения на языке C# дана в примере 5.3.2.1.

Пример 5.3.2.1. Реализация второго этапа разработки Program-приложения на языке C#.

////////////////////

// C# File Program2.cs

// Файл Program2.cs полностью включает файл Program.cs, дополнив его

// нижеследующим описанием класса Program и изменённой функцией Main

. . .

//-------------------------------------Program

{[] ship;num;

int s1, s2; // Номера встретившихся кораблей

Thread th;live;

// КонстукторProgram()

{= 1; // стартовое кол-во кораблей= new Ship[10]; // Массив из 10 кораблей

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{[i] = new Ship(i); // Создаем новый объект-корабль и помещаем его в массив

}= true; // стартуем поток= new Thread(new ThreadStart(run));

th.Start();

}

// потоковая функцияrun()

{(live)

{

// перебираем корабли(int i = 0; i < num; i++)

{(int j = i + 1; j < num; j++)

{(i < j) // Уступает корабль с бОльшим номером

{= j;= i;

}

{= i;= j;

}(Math.Abs(ship[s1].X - ship[s2].X) < 20 && Math.Abs(ship[s1].Y - ship[s2].Y) < 20)

{[s2].vstrecha = true; // Встреча началась(!ship[s1].isStopped && !ship[s2].isStopped) ship[s2].Stop();if (ship[s2].vstrecha)

{[s2].Start(); // Если пропускал, то продолжить движение

ship[s2].vstrecha = false; // Встреча

}

}.Sleep(31);

}

}

}

// основная функцияvoid Main()

{prog = new Program();.Run(prog);

}

}

.3 Этап 3. Разработка события but

Включим в класс Ship обычного объекта событие ev и уведомление, сигнализирующее об очередном цикле выполнения потока. Это событие и уведомление обрабатывается функцией MainEvent или update() класса Program, что будет использовано при перерисовке кораблей в области клиента прикладного окна на четвёртом этапе. На рис. 5.3.3.1 и в примере 5.3.3.1 представлены диаграмма классов третьего этапа и программа, реализующая её.

Рис. 5.3.3.1. Диаграмма классов приложения третьего этапа

Пример 5.3.3.1. Реализация третьего этапа разработки приложения.

////////////////////

// С# File Program3.cs

// Файл Program3.cs полностью включает файл Program2.cs, дополнив

// его объявлением события ev в классе Ship и функцией MainEvent

// класса Program, обеспечивающей обработку этого события.

// Изменения файла Program2.cs выделены жирным шрифтом.

. . .

//-------------------------------------void delEv ( ); // Объявление типа delEv делегата события ev

class Ship

{event delEv ev; // Объявление события ev

. . .

//---------------Move ( ) // Выполнить поток

{(live)

{+= speedX;+= speedY;.WriteLine("Координаты: " + System.Convert.ToString(x) + ", " + System.Convert.ToString(y));

Thread.Sleep(60); // спим(ev != null) // Если событие активизировано, то

{.WriteLine (" Event");( ); // вызвать событие

}.Sleep (10);

}

}

};

//-------------------------------------Program // Класс потоковых объектов

{[] pShip;MainEvent ( ) // Обработчик события ev

{.WriteLine (" MainEvent");

}

Program ( ) // Конструктор

{= 1; // стартовое кол-во кораблей= new Ship[10]; // Массив из 10 кораблей

for (int i = 0; i < num; i++)

{[i] = new Ship(i);[i].ev += new delEv(MainEvent); // Добавить

}= true; // стартуем поток= new Thread(new ThreadStart(run));

th.Start();

}

. . .

}

.4 Этап 4. Разработка класса основного окна и графики

Наступил этап разработки, когда появится прикладное окно приложения с перемещающимися кораблями.

Наследовав класс Form или Frame, класс Program существенно расширит свою функциональность. Теперь можно создать прикладное окно (основную форму) и дочернее окно (дочернюю форму). Но дочернее окно будет создано потом в классе Controls, также порождённом из класса Form или Frame. Пока мы добавляем в класс Ship новые переменные, необходимые для задания его траектории, и описываем эту траекторию в потоковой функции корабля Move. Потоковая функция класса Program, отслеживающая взаимодействие кораблей, также изменяется: теперь при встрече корабль с бОльшим номером будет притормаживать, не мешая соседнему. Диаграмма классов и реализация этого этапа представлены на рис. 5.3.4.1 и в примере 5.3.4.1.


Рис. 5.3.4.1. Диаграмма классов Program-приложения четвёртого этапа

Пример 5.3.4.1. Реализация четвёртого этапа разработки Program-приложения на языке C#.

////////////////////

// C# File Program4.cs

// Файл Program4.cs полностью включает файл Program3.cs, дополнив его

// данными класса Program, необходимыми для рисования кораблей, и

// свойствами класса Ship для работы с его переменными.

// В результате наследования класса Program из базового класса Form появилось

// прикладное окно, свойства которого установлены в конструкторе класса

// Program. Переопределена функция OnPaint перерисовки. Функция MainEvent,

// реагируя на событие ev из потоков, вызывает перерисовку кораблей.

// Функция run «притормаживает» корабли при встречах.

// Изменения файла Program3.cs выделены жирным шрифтом

using System;System.Drawing;System.Windows.Forms;System.Threading;Ship

{th;id; // Порядковый номер корабляbool live;double x, y; // позицияdouble speedX, speedY; // скоростьbool WasOnMoon; // был ли на Луне

protected bool start1; // только что стартовалbool comeback1; // первое возвращениеbool vstrecha; // индикатор встречи

void Move()

{(live) // пока поток жив

{((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{(WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{= -Math.PI / 2 - 0.2;= false;

}= 6 * Math.Cos(fi);= -6 * Math.Sin(fi);-= 0.16;

if (fi > Math.PI / 2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}// Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки(comeback1 && x < 230)

{= -Math.PI / 2;= false;

}(!comeback1)

{= 6 * Math.Cos(fi);= 6 * Math.Sin(fi);-= 0.05;-= 0.05;

}

}

}(x == 160 && y > 225 && y < 235) // Земля - Луна

{= -speedY + 3;

}; (x > 465 && x < 630 && y < 180) // Орбита Луны

{(!WasOnMoon)

{= Math.PI+0.4;= true;= true;

}= 4*Math.Cos(fi);= -4*Math.Sin(fi);+= 0.04;(fi > Math.PI*2-0.3 || fi < Math.PI/2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}

/*if (x > 461 && x < 630) // Орбита Луны (старое)

{(kM)

{= Math.PI+0.36;= false;

}= 4*Math.Cos(fi);= -4*Math.Sin(fi);-= 0.065;

}*/+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) // изменяем угол фи

{(x > 425) fi += 0.051;fi += 0.032;

}fi = 0;(ev != null) ev(); // событие.Sleep(60); // спим

}

}int X

{{ return (int)x; } // чтение координаты х

}int Y

{{ return (int)y; } // чтение координаты х

}double setY

{{ y = value; } // запись координаты у

}double setX

{{ x = value; } // запись координаты х

}bool isStopped { get { return !this.th.IsAlive; } }

}

//-------------------------------------Program : Form

{[] ship;

int num;s1, s2; // Номера встретившихся кораблей

Thread th;live;Program ( )

{= 1;= "Objects";= new Size(675, 675); = FormBorderStyle.FixedSingle;+= new FormClosedEventHandler(exit);.Show(); = new Point(200, 50); = new Ship[10]; (int i = 0; i < num; i++)

{[i] = new Ship(i);[i].ev += new delEv(MainEvent);

}= true;= true;= new Thread(new ThreadStart(run));

th.Start();

}

// потоковая функцияrun()

{(live)

{

// перебираем корабли(int i = 0; i < num; i++)

{(int j = i + 1; j < num; j++)

{(i < j) // Уступает корабль с бОльшим номером

{= j;= i;

}

{= i;= j;

}(Math.Abs(ship[s1].X - ship[s2].X) < 20 && Math.Abs(ship[s1].Y - ship[s2].Y) < 20)

{[s2].vstrecha = true; // Встреча началась(!ship[s1].isStopped && !ship[s2].isStopped) ship[s2].Stop();

}if (ship[s2].vstrecha)

{[s2].Start(); [s2].vstrecha = false;

}

}.Sleep(31);

}

}

// перерисовка содержимого окнаoverride void OnPaint (PaintEventArgs arg)

{grayPen = new Pen(Color.LightGray);blackPen = new Pen(Color.Black);blackBrush = new SolidBrush(Color.Black);whiteBrush = new SolidBrush(Color.White);greenBrush = new SolidBrush(Color.Lime);ArialF = new Font("Arial", 10);.Graphics.FillRectangle(blackBrush,0,0,1280,960); // Фон.Graphics.DrawEllipse(grayPen, 40, 230, 370, 370); // Орбита Земли.Graphics.DrawEllipse(grayPen, 468, 28, 162, 162); // Орбита Луны.Graphics.FillEllipse(new SolidBrush(Color.DeepSkyBlue), 100, 290, 250, 250); // Земля.Graphics.FillEllipse(new SolidBrush(Color.DarkKhaki), 500, 60, 100, 100); // Луна(int i = 0; i < num; i++) // перебираем корабли

{.Graphics.FillEllipse(greenBrush, ship[i].X, ship[i].Y, 16, 16); // корабль.Graphics.DrawEllipse(blackPen, ship[i].X, ship[i].Y, 16, 16); // обводим корабль.Graphics.DrawString(ship[i].id + "", ArialF, blackBrush, ship[i].X + 4, ship[i].Y); // номер

}

}MainEvent ( )

{.WriteLine (" MainEvent");( );

}

. . .void Main()

{prog = new Program();м.EnableVisualStyles();.Run(prog);

}

}

5.5 Этап 5. Разработка дочерних окон

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

Рис 5.3.5.1. Диаграмма классов Program-приложения пятого этапа

Пример 5.3.5.1. Реализация пятого этапа разработки Program-приложения на языке C#.

////////////////////

// C# File Program5.cs

// Файл Program5.cs полностью включает файл Program4.cs, дополнив его

// новым классом Controls, порождённым из класса Form. Класс Controls

// содержит управляющие элементы-кнопки и текстовое поле.

// Изменения файла ProgramCs4.cs выделены жирным шрифтом

. . .Controls : Form // Класс пользователя кораблей

{AddShip; // Добавить новый корабльAddFuel; // Добавить топливоPause; // Приостановка всех кораблейnumShip; // Номер корабля, которому добавляется топливо[] Koord;[] Sost; // Сообщения о состоянии кораблейevent delBut but; // Привязываем к делегату события нажатия кнопок

// конструкторControls()

{

// кнопки= new Button();.Location = new Point(10, 50);.Text = "Добавить корабль";.Size = new Size(120, 25);.Click += new EventHandler(onAdd);= new Button();.Location = new Point(10, 80);.Text = "Добавить топливо";.Size = new Size(120, 25);.Click += new EventHandler(onAddFuel);= new Button();.Location = new Point(20, 110);.Size = new System.Drawing.Size(100, 25);.Text = "Пауза";.Click += new EventHandler(onPause);

// текстовое поле= new TextBox();.Location = new Point(35, 20);.Text = "0";.Size = new Size(65, 25);= new Point[10];(int i = 0; i < 10; i++ )[i] = new Point(15, i*21 + 5);= new TextBox[10];;(int i = 0; i < 10; i++)

{[i] = new TextBox();[i].Location= Koord[i];[i].Text = Convert.ToString(i)+". Не запущен";[i].Size = new Size(90, 20);

}[0].Text = "0. В полёте";

// окошко с кнопками управления

Form ctrl = new Form();.Text = "Controls";.Size = new Size(150, 200);.Controls.Add(AddShip);.Controls.Add(AddFuel);.Controls.Add(Pause);.Controls.Add(numShip);.Show(); // показываем окно

ctrl.Location = new Point(10, 50); // позиционируем

// окошко с информацией

Form Info = new Form();.Text = "Info";.Size = new Size(150, 260);(int i = 0; i < 10; i++ ) Info.Controls.Add(Sost[i]); // Массив сообщений во 2 окне.Location = new Point(10, 50); // позиционируем.Show(); // показываем окно.Location = new Point(10, 250);.Show();

}void SetStatus (int num, string str)

{.Sost[num].Text = Convert.ToString(num) + ". " + str;

}bool IsntDisappeared(int i) // Проверка статуса на "исчезновение"

{(Sost[i].Text == Convert.ToString(i) + ". Исчез")false;return true;

}

// обработчик кнопки добавления корабляonAdd(object obj, EventArgs arg)

{(but != null) but("add", 0);

}

// обработчик кнопки приостановкиonPause(object obj, EventArgs arg)

{(but != null)

{(Pause.Text == "Пауза")

{.Text = "Старт"; // меняем текст кнопки("stop", 0); // генерируем событие приостановки

}

{.Text = "Пауза";("start", 0); // генерируем событие запуска

}

}

}

// обработчик кнопки добавления топливаonAddFuel(object obj, EventArgs arg)

{(but != null) but("fuel", Convert.ToInt32(this.numShip.Text));

}

} Program: Form

{Program()

{

. . .= new Controls();.but += new delBut(ButPressed); // привязываем события нажатия кнопок

. . .

}ButPressed(string btn, int numship)

{(btn == "add")

{(num < 10)

{ // если кол-во < 10[num] = new Ship(num); // создаём[num].ev += new delEv(MainEvent); // привязываем.SetStatus(num, "В полёте");++;

}

{.Show("Не больше 10!");

}

}if (btn == "start")

{(int i = 0; i < num; i++)

{(ContForm.IsntDisappeared(i))

{[i].Start(); // стартуем все корабли, кроме исчезнувших.SetStatus(i, "В полёте");

}

}

}if (btn == "stop")

{(int j = 0; j < num; j++)

{(ContForm.IsntDisappeared(j))

{[j].Stop(); // приостанавливаем все корабли.SetStatus(j, "Остановлен");

}

}

}if (btn == "fuel") // добавляем 20 единиц топлива

{[numship].fuel += 20;(ship[numship].fuel > 99) ship[numship].fuel = 99; }

}

}

}

.6 Этап 6. Разработка специального объекта (заправщик)

В последнем этапе разработаем класс Charger специального объекта (заправщика), добавим его объект в класс, содержащий массив обычных объектов. Заправщик должен постоянно находиться на орбите Земли, двигаясь против часовой стрелки и добавляя топливо кораблям при сближении. Создадим специальный объект в теле конструктора класса Program. Добавим в потоковую функцию, отслеживающую сближение кораблей, обработку их взаимодействия с заправщиком. Диаграмма классов и реализация последнего этапа представлены на рис. 5.3.7.1 и в примере 5.3.7.1.


Рис. 5.3.7.1. Диаграмма классов приложения шестого этапа

Пример 5.3.7.1. Реализация шестого этапа разработки приложения на языке C#.

////////////////////

// C# File Program6.cs

// Файл Program6.cs полностью включает файл Program5.cs, дополнив его новым

// классом Charger специального объекта. В классе Program создан

// специальный объект, потоковая функция класса Program дополнена.

// Изменения файла ProgramCs6.cs выделены жирным шрифтом

. . .Charger : Ship // Класс заправщика

{Charger(): base(10)

{.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли).x = 230;.fi = -Math.PI / 2 - 0.05; // начальная позиция на орбите(); // останавливаем запущенный поток(); // запускаем движение

}void StartCh()

{(live == false)

{.Abort(); // Отключаем стандартный поток кораблей

live = true;= new Thread(new ThreadStart(Move)); // Создаем новый поток.Start(); // Стартуем поток

}

}Move()

{(live)

{= 12 * Math.Cos(fi);= 12 * Math.Sin(fi);(y > 415) y -= 0.27; else y -= 0.05;+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) fi += 0.065; // изменяем угол фиfi = 0;.Sleep(60); // спим

}

}

}

//-------------------------------------Program : Form // Класс потоковых объектов

{[] ship;charger;ContForm;

int num;s1, s2; // Номера встретившихся кораблей

Thread th;live;Program()

{

. . .= new Ship[10]; // Массив из 10 кораблей

charger = new Charger();

. . .

}run()

{(live)

{(int i = 0; i < num; i++)

{(Math.Abs(ship[i].X - charger.X) < 20 && Math.Abs(ship[i].Y - charger.Y) < 20) // Заправка(!charger.isStopped)

{(ship[i].fuel <= 89) ship[i].fuel += 10; else ship[i].fuel = 99;

}(ship[i].fuel <= 0) // Исчезновение

{[i].Stop();[i].setX = 1000;[i].setY = 1000 + 50*i;.Invoke(new EventHandler(delegate // Сообщение статуса

{.SetStatus(i, "Исчез");

}));

. . .

}

}

. . .

//---------------override void OnPaint (PaintEventArgs arg) // Перерисовать

{

. . ..Graphics.FillEllipse(new SolidBrush(Color.DarkRed), charger.X, charger.Y, 16, 16); // заправщик.Graphics.DrawEllipse(blackPen, charger.X, charger.Y, 16, 16); .Graphics.DrawString("C", ArialF, blackBrush, charger.X + 2, charger.Y);

}

. . .

}

. . .

6. Описание проблем, возникших при разработке программной системы

При переводе программы на язык Java возникли трудности с описанием уведомлений и потоков. При отладке пришлось изменить порядок создания объектов классов и размещение обработчиков.

Список используемой литературы

. Медведев В.И. Особенности объектно-ориентированного программирования на C++/CLI, C# и Java - Казань: РИЦ «Школа», 2010. - 444 c.: ил. - (Серия «Современная прикладная математика и информатика»).

. Веб-ресурс #"722797.files/image008.gif">

Приложение 2. Текст программы на языке C#

using System;System.Drawing;System.Windows.Forms;System.Threading;Unite

{void delEv(); // делегат событияvoid delBut(string btn, int numship); // делегат события кнопок

// класс формы с кнопкамиControls

{AddShip; // Добавить новый корабльAddFuel; // Добавить топливоPause; // Приостановка всех кораблейnumShip; // Номер корабля, которому добавляется топливо[] Koord;[] Sost; // Сообщения о состоянии кораблейevent delBut but; // Привязываем к делегату события нажатия кнопок

// конструктор формыControls()

{

// кнопки= new Button();.Location = new Point(10, 50);.Text = "Добавить корабль";.Size = new Size(120, 25);.Click += new EventHandler(onAdd);= new Button();.Location = new Point(10, 80);.Text = "Добавить топливо";.Size = new Size(120, 25);.Click += new EventHandler(onAddFuel);= new Button();.Location = new Point(20, 110);.Size = new System.Drawing.Size(100, 25);.Text = "Пауза";.Click += new EventHandler(onPause);

// текстовое поле= new TextBox();.Location = new Point(35, 20);.Text = "0";.Size = new Size(65, 25);= new Point[10];(int i = 0; i < 10; i++ )[i] = new Point(15, i*21 + 5);= new TextBox[10];;(int i = 0; i < 10; i++)

{[i] = new TextBox();[i].Location= Koord[i];[i].Text = Convert.ToString(i)+". Не запущен";[i].Size = new Size(90, 20);

}[0].Text = "0. В полёте";

// окошко с кнопками управления

Form ctrl = new Form();.Text = "Controls";.Size = new Size(150, 200);.Controls.Add(AddShip);.Controls.Add(AddFuel);.Controls.Add(Pause);.Controls.Add(numShip);.Show(); // показываем окно

ctrl.Location = new Point(10, 50); // позиционируем

// окошко с информацией

Form Info = new Form();.Text = "Info";.Size = new Size(150, 260);(int i = 0; i < 10; i++ ) Info.Controls.Add(Sost[i]); // Массив сообщений во 2 окне.Location = new Point(10, 50); // позиционируем.Show(); // показываем окно.Location = new Point(10, 250);.Show();

}void SetStatus (int num, string str)

{.Sost[num].Text = Convert.ToString(num) + ". " + str;

}bool IsntDisappeared(int i) // Проверка статуса на "исчезновение"

{(Sost[i].Text == Convert.ToString(i) + ". Исчез")false;return true;

}

// обработчик кнопки добавления корабляonAdd(object obj, EventArgs arg)

{(but != null) but("add", 0);

}

// обработчик кнопки приостановкиonPause(object obj, EventArgs arg)

{(but != null)

{(Pause.Text == "Пауза")

{.Text = "Старт"; // меняем текст кнопки("stop", 0); // генерируем событие приостановки

}

{.Text = "Пауза";("start", 0); // генерируем событие запуска

}

}

}

// обработчик кнопки добавления топливаonAddFuel(object obj, EventArgs arg)

{(but != null) but("fuel", Convert.ToInt32(this.numShip.Text));

}

}

// Класс корабля.Ship

{Thread th;

public int id; // Порядковый номер корабля

protected bool live;double x, y; // позицияdouble speedX, speedY; // скоростьdouble fi; // положение на окружности орбитыdouble fuel; // топливоbool WasOnMoon; // был ли на Луне

protected bool start1; // только что стартовалbool comeback1; // первое возвращениеbool vstrecha; // индикатор встречиevent delEv ev; // событие смены движения, по которому взаимодействуют корабли

// Конструктор класса. Принимает номер корабля.Ship(int ns)

{.id = ns; // Записываем номер корабля.live = false; // первоначально не движемся.x = 160; // начальная позиция (поверхность Земли).y = 300; // начальная позиция по высоте (поверхность Земли).speedX = 0; // скорость движения по горизонтали.speedY = -3; // скорость движения по вертикали (старт с Земли).fuel = 50; // начальный запас топлива.fi = Math.PI;.WasOnMoon = false; // на Луне не был .start1 = true; // первый старт - да.comeback1 = false; // первое возвращение - нет.vstrecha = false; // встречи нет(); // запускаем движение

}

// функция старта потока движения корабляvoid Start()

{(live == false)

{= true;= new Thread(new ThreadStart(Move)); // Создаем объект-поток "движение корабля"

th.Start(); // Стартуем поток

}

}

// функция остановки потока движения корабля

public void Stop()

{= false;

}

// Поток, отвечающий за движение корабляMove()

{(live) // пока поток жив

{((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{(WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{= -Math.PI / 2 - 0.2;= false;

}= 6 * Math.Cos(fi);= -6 * Math.Sin(fi);-= 0.16;

if (fi > Math.PI / 2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}// Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки(comeback1 && x < 230)

{= -Math.PI / 2;= false;

}(!comeback1)

{= 6 * Math.Cos(fi);= 6 * Math.Sin(fi);-= 0.05;-= 0.05;

}

}

}(x == 160 && y > 225 && y < 235) // Земля - Луна

{= -speedY + 3;

}; (x > 465 && x < 630 && y < 180) // Орбита Луны

{(!WasOnMoon)

{= Math.PI+0.4;= true;= true;

}= 4*Math.Cos(fi);= -4*Math.Sin(fi);+= 0.04;(fi > Math.PI*2-0.3 || fi < Math.PI/2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}

/*if (x > 461 && x < 630) // Орбита Луны (старое)

{(kM)

{= Math.PI+0.36;= false;

}= 4*Math.Cos(fi);= -4*Math.Sin(fi);-= 0.065;

}*/+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) // изменяем угол фи

{(x > 425) fi += 0.051;fi += 0.032;

}fi = 0;(ev != null) ev(); // событие.Sleep(60); // спим

}

}

// публичные сеттеры/геттерыint X

{{ return (int)x; } // чтение координаты х

}int Y

{{ return (int)y; } // чтение координаты х

}double setY

{{ y = value; } // запись координаты у

}double setX

{{ x = value; } // запись координаты х

}bool isStopped { get { return !this.th.IsAlive; } }

}Charger : Ship // Класс заправщика

{Charger(): base(10)

{.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли).x = 230;.fi = -Math.PI / 2 - 0.05; // начальная позиция на окружности орбиты(); // останавливаем запущенный поток для движения кораблей(); // запускаем движение по стабильной орбите против часовой стрелки

}void StartCh()

{(live == false)

{.Abort(); // Отключаем стандартный поток кораблей

live = true;= new Thread(new ThreadStart(Move)); // Создаем новый поток с другой функцией движения.Start(); // Стартуем поток

}

}Move()

{(live) // пока поток жив

{

speedY = 12 * Math.Cos(fi);= 12 * Math.Sin(fi);(y > 415) y -= 0.27; else y -= 0.05;+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) fi += 0.065; // изменяем угол фиfi = 0;.Sleep(60); // спим

}

}

}

// основной класс, использующий формыProgram : Form

{[] ship;charger;ContForm;

int num;s1, s2; // Номера встретившихся кораблей

Thread th;live;

// КонстукторProgram()

{= 1; // стартовое кол-во кораблей= "Objects"; // заголовок окна

Size = new Size(675, 675); // размер окна= FormBorderStyle.FixedSingle;+= new FormClosedEventHandler(exit);.Show(); // показываем= new Point(200, 50); // позиционируем окно= new Controls(); // подключаем класс формы с кнопками управления.but += new delBut(ButPressed); // привязываем события нажатия кнопок

ship = new Ship[10]; // Массив из 10 кораблей

charger = new Charger();(int i = 0; i < num; i++) // Перебираем массив кораблей

{[i] = new Ship(i); // Создаем новый объект-корабль и помещаем его в массив

ship[i].ev += new delEv(MainEvent); // привязываем обработчик событий

}= true; // буферизация - устраняет мелькание= true; // стартуем= new Thread(new ThreadStart(run));

th.Start();

}

// потоковая функцияrun()

{(live)

{

// перебираем корабли(int i = 0; i < num; i++)

{(Math.Abs(ship[i].X - charger.X) < 20 && Math.Abs(ship[i].Y - charger.Y) < 20) // Заправка(!charger.isStopped)

{(ship[i].fuel <= 89) ship[i].fuel += 10; else ship[i].fuel = 99;

}(ship[i].fuel <= 0) // Если кончается топливо, корабль "исчезает".

{[i].Stop();[i].setX = 1000;[i].setY = 1000 + 50*i;.Invoke(new EventHandler(delegate // Сообщение статуса

{.SetStatus(i, "Исчез");

}));

}(int j = i + 1; j < num; j++)

{(i < j) // Уступает корабль с бОльшим номером

{= j;= i;

}

{= i;= j;

}(Math.Abs(ship[s1].X - ship[s2].X) < 20 && Math.Abs(ship[s1].Y - ship[s2].Y) < 20)

{[s2].vstrecha = true; // Встреча началась(!ship[s1].isStopped && !ship[s2].isStopped) ship[s2].Stop();.Invoke(new EventHandler(delegate

{(ContForm.IsntDisappeared(s2)) ContForm.SetStatus(s2, "Уступает");

}));

}if (ship[s2].vstrecha)

{[s2].Start(); // Если пропускал, то продолжить движение[s2].vstrecha = false; // Встреча закончилась

this.Invoke(new EventHandler(delegate // Сообщение статуса

{.SetStatus(s2, "В полёте");

}));

}

}

//Invalidate();.Sleep(31);

}

}

}

// обработчик события MainEvent()

{();

}

// перерисовка содержимого окнаoverride void OnPaint(PaintEventArgs arg)

{grayPen = new Pen(Color.LightGray);blackPen = new Pen(Color.Black);blackBrush = new SolidBrush(Color.Black);whiteBrush = new SolidBrush(Color.White);greenBrush = new SolidBrush(Color.Lime);ArialF = new Font("Arial", 10);.Graphics.FillRectangle(blackBrush,0,0,1280,960); // Фон.Graphics.FillRectangle(whiteBrush, 100, 150, 2, 2); // Звезды.Graphics.DrawEllipse(grayPen, 40, 230, 370, 370); // Орбита Земли.Graphics.DrawEllipse(grayPen, 468, 28, 162, 162); // Орбита Луны.Graphics.FillEllipse(new SolidBrush(Color.DeepSkyBlue), 100, 290, 250, 250); // Земля.Graphics.FillEllipse(new SolidBrush(Color.DarkKhaki), 500, 60, 100, 100); // Луна(int i = 0; i < num; i++) // перебираем корабли

{.Graphics.FillEllipse(greenBrush, ship[i].X, ship[i].Y, 16, 16); // корабль.Graphics.DrawEllipse(blackPen, ship[i].X, ship[i].Y, 16, 16); // обводим корабль.Graphics.DrawString(ship[i].id + "", ArialF, blackBrush, ship[i].X + 4, ship[i].Y); // номер.Graphics.DrawString(Math.Round(ship[i].fuel) + "", ArialF, whiteBrush, ship[i].X - 1, ship[i].Y - 15); // топливо

}.Graphics.FillEllipse(new SolidBrush(Color.DarkRed), charger.X, charger.Y, 16, 16); // заправщик.Graphics.DrawEllipse(blackPen, charger.X, charger.Y, 16, 16); // обводим корабль.Graphics.DrawString("C", ArialF, blackBrush, charger.X + 2, charger.Y); // номер

}

// обработчик событий кнопок формы управленияButPressed(string btn, int numship)

{(btn == "add")

{(num < 10)

{ // если кол-во < 10[num] = new Ship(num); // создаём[num].ev += new delEv(MainEvent); // привязываем.SetStatus(num, "В полёте");++;

}

{.Show("Не больше 10!");

}

}if (btn == "start")

{(int i = 0; i < num; i++)

{(ContForm.IsntDisappeared(i))

{[i].Start(); // стартуем все корабли, кроме исчезнувших.SetStatus(i, "В полёте");

}

}.StartCh();

}if (btn == "stop")

{(int j = 0; j < num; j++)

{(ContForm.IsntDisappeared(j))

{[j].Stop(); // приостанавливаем все корабли.SetStatus(j, "Остановлен");

}

}.Stop();

}if (btn == "fuel") // добавляем 20 единиц топлива

{

//for (int i = 0; i < num; i++) ship[i].fuel = 99; // для отладки(ship[numship] != null)

{[numship].fuel += 20;

if (ship[numship].fuel > 99) ship[numship].fuel = 99; // если значение топлива превысит 99, то устанавливается в 99

}

}

}

// событие закрытия окна, завершаем потоки и зaкрываем программу

protected override void OnClosed(EventArgs args)

{(null, null);

}

// обработчик выхода из программы

void exit(object obj, EventArgs arg)

{(int i = 0; i < num; i++)

{[i].Stop();

}.Stop();.Abort();.Join();.Exit();

}

// основная функцияvoid Main()

{prog = new Program(); // создаём ссылку на класс, инициализируем.EnableVisualStyles();.Run(prog); // запускаем программу по созданной ссылке

}

}

}

Приложение 3. Текст программы на языке Java

import java.util.*;java.awt.*;java.awt.event.*;Ship extends Observable implements Runnable// Класс корабля

{Thread th;int id; // Порядковый номер корабляboolean live;double x, y; // позицияdouble speedX, speedY; // скоростьdouble fi; // положение на окружности орбитыdouble fuel; // топливоboolean WasOnMoon; // был ли на Лунеboolean start1; // только что стартовалboolean comeback1; // первое возвращениеboolean vstrecha; // индикатор встречиShip(int ns)// Конструктор

{.id = ns; // Записываем номер корабля.live = false; // первоначально не движемся.x = 160; // начальная позиция (поверхность Земли).y = 300; // начальная позиция по высоте (поверхность Земли).speedX = 0; // скорость движения по горизонтали.speedY = -3; // скорость движения по вертикали (старт с Земли).fuel = 50; // начальный запас топлива.fi = Math.PI;.WasOnMoon = false; // на Луне не был .start1 = true; // первый старт - да.comeback1 = false; // первое возвращение - нет.vstrecha = false; // встречи нет(); // запускаем движение

}void Start() // Функция старта

{(live == false)

{= true;= new Thread(this); // Создаем объект-поток "движение корабля".start(); // Стартуем поток

}

}void Stop()// Функия остановки

{= false;

}void run() // Выполнить поток

{(live) // Пока существует, выполнять

{((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{(WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{= -Math.PI / 2 - 0.2;= false;

}= 6 * Math.cos(fi);= -6 * Math.sin(fi);-= 0.16;

if (fi > Math.PI / 2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}// Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки(comeback1 && x < 230)

{= -Math.PI / 2;= false;

}(!comeback1)

{= 6 * Math.cos(fi);= 6 * Math.sin(fi);-= 0.05;-= 0.05;

}

}

} (x == 160 && y > 225 && y < 235) // Земля - Луна

{= -speedY + 3;

}; (x > 465 && x < 630 && y < 180) // Орбита Луны

{(!WasOnMoon)

{= Math.PI + 0.4;= true;= true;

}= 4 * Math.cos(fi);= -4 * Math.sin(fi);+= 0.04;(fi > Math.PI * 2 - 0.3 || fi < Math.PI / 2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) // изменяем угол фи

{(x > 425) fi += 0.051;fi += 0.032;

}fi = 0;

{.sleep(60); // спим

}(InterruptedException iE) { }();(new Integer(0));

}

}

// публичные сеттеры/геттерыdouble X()

{x; // чтение координаты х

}

public double Y()

{y; // чтение координаты у

}void setY(double value)

{= value; // запись координаты у

}

public void setX(double value)

{= value; // запись координаты х

}

public boolean isStopped() { return !this.th.isAlive(); }

}Charger extends Ship// Класс заправщика

{Charger()

{(10);.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли).x = 230;.fi = -Math.PI / 2 - 0.05; // начальная позиция на окружности орбиты(); // останавливаем запущенный поток для движения кораблей(); // запускаем движение по стабильной орбите против часовой стрелки

}void StartCh()

{(live == false)

{.interrupt(); // Отключаем стандартный поток кораблей= true;= new Thread(this); // Создаем новый поток с другой функцией движения

th.start(); // Стартуем поток

}

}void run()

{(live) // пока поток жив

{

speedY = 9 * Math.cos(fi);= 9 * Math.sin(fi);(y > 415) y -= 0.21;+= speedX; y += speedY; // движемся(fi < 2 * Math.PI) fi += 0.049; // изменяем угол фиfi = 0;

{.sleep(60); // спим

}(InterruptedException iE) { }();(new Integer(0));

}

}

}Program extends Frame implements Observer// Класс формы с объектами

{[] ship;charger;int num;

int s1, s2; // Номера встретившихся кораблей

private double dx, dy;th;boolean live;int numship;

public Program() // Конструктор

{= 1; // стартовое кол-во кораблей.setTitle("Objects"); // заголовок окна.setSize(675, 675); // размер окна

this.setResizable(false);.setLocation(200, 50);// позиционируем окно

ship = new Ship[10]; // Массив из 10 кораблей (макс)

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{[i] = new Ship(i); // Создаем новый объект-корабль и помещаем его в массив[i].addObserver(this);// привязываем обработчик событий

}

charger = new Charger();.addObserver(this);.addWindowListener(new WindowAdapter()// Обработчик закрытия программы

{void windowClosing(WindowEvent wE)

{(null, null);

});.show();

}void update(Observable obj, Object arg) // Обработчик события встречи

{(int i = 0; i < num; i++)

{(Math.abs(ship[i].X() - charger.X()) < 20 && Math.abs(ship[i].Y() - charger.Y()) < 20) // Заправка(!charger.isStopped())

{(ship[i].fuel <= 89) ship[i].fuel += 10; else ship[i].fuel = 99;

}(ship[i].fuel <= 0) // Если кончается топливо, корабль "исчезает".

{[i].Stop();[i].setX(1000);[i].setY(1000 + 50*i);

}(int j = i + 1; j < num; j++)

{(i < j) // Уступает корабль с бОльшим номером

{= j;= i;

}

{= i;= j;

}(Math.abs(ship[s1].X() - ship[s2].X()) < 20 && Math.abs(ship[s1].Y() - ship[s2].Y()) < 20)

{[s2].vstrecha = true; // Встреча началась(!ship[s1].isStopped() && !ship[s2].isStopped()) ship[s2].Stop();

}if (ship[s2].vstrecha)

{[s2].Start(); // Если пропускал, то продолжить движение[s2].vstrecha = false; // Встреча закончилась

}

}

}();

}void paint(Graphics arg)

{.paint(arg);gray = Color.gray;darkGray = Color.darkGray;black = Color.black;white = Color.white;(new Color(0, 0, 0)); // Фон.setColor(gray);.drawOval(40, 230, 370, 370); // Орбита Земли.drawOval(468, 28, 162, 162); // Орбита Луны.setColor(new Color(0, 128, 255));.fillOval(100, 290, 250, 250); // Земля.setColor(new Color(128, 128, 64));.fillOval(500, 60, 100, 100); // Луна(int i = 0; i < num; i++) // перебираем корабли

{.setColor(new Color(0, 255, 64));.fillOval(System.Convert.ToInt32(ship[i].X()), System.Convert.ToInt32(ship[i].Y()), 16, 16); // корабль.setColor(darkGray);.drawOval(System.Convert.ToInt32(ship[i].X()), System.Convert.ToInt32(ship[i].Y()), 16, 16); // обводим корабль.setColor(black);.drawString(System.Convert.ToString(ship[i].id), System.Convert.ToInt32(ship[i].X() + 4), System.Convert.ToInt32(ship[i].Y()+12)); // номер.setColor(white);.drawString(System.Convert.ToString(Math.round(ship[i].fuel)), System.Convert.ToInt32(ship[i].X() - 1), System.Convert.ToInt32(ship[i].Y() - 3));

}.setColor(new Color(128, 0, 0));.fillOval(System.Convert.ToInt32(charger.X()), System.Convert.ToInt32(charger.Y()), 16, 16); // заправщик.setColor(black);.drawOval(System.Convert.ToInt32(charger.X()), System.Convert.ToInt32(charger.Y()), 16, 16); // обводим корабль.drawString("C", System.Convert.ToInt32(charger.X() + 4), System.Convert.ToInt32(charger.Y()+12)); // номер

}

// обработчик выхода из программыExit(Object obj, System.EventArgs arg)

{(int i = 0; i < num; i++)

{[i].Stop();[i].th.interrupt();

}.Stop();.th.interrupt();.exit(0);

}

}Controls extends Frame implements ActionListener // Класс окон с кнопками

{prog;// Форма с объектамиAddShip; // Добавить новый корабльAddFuel; // Добавить топливоPause; // Приостановка всех кораблейnumShip; // Номер корабля, которому добавляется топливо[] Koord;[] Sost; // Сообщения о состоянии кораблей

Frame ctrl, Info;Controls()

{= new Program();// Создаем окно с объектами

// текстовое поле= new TextField();.setLocation(35, 20);.setText("0");.setSize(65, 25);

// кнопки= new Button("Добавить корабль");.setLocation(10, 50);.setSize(120, 25);.addActionListener(new ActionListener()

{void actionPerformed(ActionEvent aE)

{(prog.num < 10)

{ // если кол-во < 10

prog.ship[prog.num] = new Ship(prog.num); // создаём.ship[prog.num].addObserver(prog); // привязываем(prog.num, "В полёте");.num++;

}

{.Windows.Forms.MessageBox.Show("Не больше 10!");

}

}

});= new Button("Добавить топливо");.setLocation(10, 80);.setSize(120, 25);.addActionListener(new ActionListener()

{void actionPerformed(ActionEvent aE)

{(prog.ship[System.Convert.ToInt32(numShip.getText())] != null)

{.ship[System.Convert.ToInt32(numShip.getText())].fuel += 20;(prog.ship[System.Convert.ToInt32(numShip.getText())].fuel > 99).ship[System.Convert.ToInt32(numShip.getText())].fuel = 99;

}

}

});= new Button("Пауза");.setLocation(20, 110);.setSize(100, 25);.addActionListener(new ActionListener()

{void actionPerformed(ActionEvent aE)

{(Pause.getLabel() == "Пауза")

{(int i = 0; i < prog.num; i++)// генерируем событие приостановки

{.ship[i].Stop();(i, "Остановлен");

}.charger.Stop();.setLabel("Старт");// меняем текст кнопки

}

{(int i = 0; i < prog.num; i++)// генерируем событие запуска

{.ship[i].Start();(i, "В полете");

}.charger.Start();.setLabel("Пауза");

}

}

});.addWindowListener(new WindowAdapter()

{void windowClosing(WindowEvent wE)

{.exit(0);

}

});= new Point[10];(int i = 0; i < 10; i++)[i] = new Point(15, i * 21 + 40);= new TextField[10];(int i = 0; i < 10; i++)

{[i] = new TextField();[i].setLocation(Koord[i]);[i].setText(System.Convert.ToString(i) + ". Не запущен");[i].setSize(90, 20);

}[0].setText("0. В полёте");

// окошко с кнопками управления

ctrl = new Frame("Controls");.setSize(150, 200);.setLayout(new FlowLayout());.setLocation(10, 50);.add(AddShip);.add(AddFuel);.add(Pause);.add(numShip);.setVisible(true);.show();

// окошко с информацией= new Frame("Info");.setSize(150, 260);(int i = 0; i < 10; i++).add(Sost[i], new Point()); // Массив сообщений во 2 окне.setLocation(10, 250);.setVisible(true);.show();.addActionListener(this);.addActionListener(this);.addActionListener(this);

}void SetStatus(int num, String str)

{.Sost[num].setText(System.Convert.ToString(num) + ". " + str);

}boolean IsntDisappeared(int i) // Проверка статуса на "исчезновение"

{(Sost[i].getText() == System.Convert.ToString(i) + ". Исчез")false;return true;

}void actionPerformed(ActionEvent aE)

{

//repaint();//Перерисовать

}static void main()

{MainForm = new Controls();.show();

}

}

Приложение 4. Текст программы на языке C++/CLI

// UniteCPP.cpp : main project file.

#include "stdafx.h"

#include "Form1.h"

#using <System.dll>

#using <System.Windows.Forms.dll>

#using <System.Drawing.dll>namespace System::Threading;namespace UniteCPP;delegate void delBut(String ^btn, int numship); // делегат события кнопок

// класс формы с кнопкамиclass ButtonForm : Form

{^ctrl; // Форма с кнопками^Info;^AddShip; // Добавить новый корабль^AddFuel; // Добавить топливо

Button ^pause; // Приостановка всех кораблей^numShip; // Номер корабля, которому добавляется топливо< TextBox^ > ^Sost; // Сообщения о состоянии кораблей: event delBut ^but; // Привязываем к делегату события нажатия кнопок

// конструктор формы: ButtonForm()

{

// кнопки= gcnew Button();

AddShip->Location = Point(10, 50);>Text = "Добавить корабль";>Size = System::Drawing::Size(120, 25);>Click += gcnew EventHandler(this, &ButtonForm::onAdd);= gcnew Button();>Location = Point(10, 80);>Text = "Добавить топливо";>Size = System::Drawing::Size(120,25);>Click += gcnew EventHandler(this, &ButtonForm::onAddFuel);= gcnew Button();>Location = Point(20, 110);>Size = System::Drawing::Size(100, 25);>Text = "Пауза";>Click += gcnew EventHandler(this, &ButtonForm::onPause);= gcnew TextBox();>Location = Point(35, 20);>Text = "0";>Size = Drawing::Size(65, 25);= gcnew array< TextBox^ >(10);;(int i = 0; i < 10; i++)

{[i] = gcnew TextBox();[i]->Location = Point(15, i*21 + 5); //Koord[i];[i]->Text = Convert::ToString(i)+". Не запущен";[i]->Size = System::Drawing::Size(90, 20);

}[0]->Text = "0. В полёте";

//окошко с кнопками управления

ctrl = gcnew Form();>Location = Point(10,50);// позиционируем>Text = "Controls";>ClientSize = System::Drawing::Size(150,150);>Controls->Add(AddShip);>Controls->Add(AddFuel);>Controls->Add(pause);>Controls->Add(numShip);

// окошко с информацией= gcnew Form();

Info->Text = "Info";>ClientSize = System::Drawing::Size(110, 230);(int i = 0; i < 10; i++ ) Info->Controls->Add(Sost[i]); // Массив сообщений во 2 окне>Location = Point(10, 50); // позиционируем>Show(); // показываем окно>Location = Point(10, 250);>Show();

}: void SetStatus (int num, String ^str)

{>Sost[num]->Text = Convert::ToString(num) + ". " + str;

}: bool IsntDisappeared(int i) // Проверка статуса на "исчезновение"

{(Sost[i]->Text == Convert::ToString(i) + ". Исчез")false;return true;

}

// обработчик кнопки добавления корабляonAdd(System::Object^ sender, EventArgs^ e)

{("add", 0);

}

// обработчик кнопки приостановкиonPause(Object^ sender, EventArgs^ e)

{(pause->Text == "Пауза")

{>Text = "Старт"; // меняем текст кнопки

but("stop", 0); // генерируем событие приостановки

}

{>Text = "Пауза";("start", 0); // генерируем событие запуска

}

};

// обработчик кнопки добавления топливаonAddFuel(Object^ sender, EventArgs^ e)

{("fuel", Convert::ToInt32(this->numShip->Text));

};

};

// Класс корабля.class Ship

{: System::Threading::Thread ^th;

public:int id; // Порядковый номер корабля

protected:bool live; : double x, y; // позиция: double speedX, speedY; // скорость: double fi; // положение на окружности орбитыstatic fi2; // Копия фи: double fuel; // топливо: bool WasOnMoon; // был ли на Луне

protected: bool start1; // только что стартовал

protected: bool comeback1; // первое возвращение: bool vstrecha;

// Конструктор класса. Принимает номер корабля.: Ship(int ns)

{>id = ns; // Записываем номер корабля>live = false; // первоначально не движемся>x = 160; // начальная позиция (поверхность Земли)>y = 300; // начальная позиция по высоте (поверхность Земли)>speedX = 0; // скорость движения по горизонтали>speedY = -3; // скорость движения по вертикали (старт с Земли)>fi = Math::PI;>fuel = 50; // начальный запас топлива>WasOnMoon = false; // изначально на Луне не был =) >start1 = true; // первый старт - да>comeback1 = false; // первое возвращение - нет>vstrecha = false; // встречи нет(); // запускаем движение

}

// функция старта потока движения корабля: void Start()

{(live == false)

{= true;= gcnew Thread(gcnew ThreadStart(this, &Ship::Move)); // Создаем объект-поток "движение корабля"

th->Start(); // Стартуем поток

}

}

// функция остановки потока движения корабля

public: void Stop()

{= false;

}

// Поток, отвечающий за движение корабляMove()

{ (live) // пока поток жив

{((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{(WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{= -Math::PI / 2 - 0.2;= false;

}= 6 * Math::Cos(fi);= -6 * Math::Sin(fi);-= 0.16;

if (fi > Math::PI/2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}// Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки(comeback1 && x < 230)

{= -Math::PI / 2;= false;

}(!comeback1)

{= 6 * Math::Cos(fi);= 6 * Math::Sin(fi);-= 0.05;-= 0.05;

}

}

} (x == 160 && y > 225 && y < 235) // Земля - Луна

{= -speedY + 3;

};  (x > 465 && x < 630 && y < 180) // Орбита Луны

{(!WasOnMoon)

{= Math::PI+0.4;= true;= true;

}= 4*Math::Cos(fi);= -4*Math::Sin(fi);+= 0.04;(fi > Math::PI*2-0.3 || fi < Math::PI/2) fuel -= 0.5; // Разгон: топливо уменьшаетсяfuel -= 0.05;

}+= speedX; y += speedY; // движемся(fi < 2 * Math::PI) // изменяем угол фи

{(x > 425) fi += 0.051;fi += 0.032;

}fi = 0;= fi;>th->Sleep(60); // спим

}

}

// публичные сеттеры/геттеры: property double X

{get() { return x ; } // чтение координаты х

};: property double Y

{get() { return Convert::ToInt32(y); } // чтение координаты у

};: property double setY

{set(double value) { y = value; } // запись координаты у

};: property double setX

{set(double value) { x = value; } // запись координаты х

};: property double spY

{get() { return Convert::ToInt32(speedY); } // чтение скорости по у

};: property double spX

{get() { return Convert::ToInt32(speedX); } // чтение скорости по х

};: property double setSpY

{set(double value) { speedY = value; } // запись скорости по у

};: property double setSpX

{set(double value) { speedX = value; } // запись скорости по х

};: property bool isStopped { bool get() { return !this->th->IsAlive; } };

};class Charger : Ship

{: Charger(): Ship(10)

{>speedY = 0;>y = 225; // начальная позиция по высоте (орбита Земли)>x = 230;>fi = -Math::PI / 2 - 0.05; // начальная позиция на окружности орбиты(); // останавливаем запущенный поток для движения кораблей(); // запускаем движение по стабильной орбите против часовой стрелки

}: void StartCh()

{(live == false)

{>th->Abort(); // Отключаем стандартный поток кораблей

live = true;>th = gcnew Thread(gcnew ThreadStart(this, &Charger::Move)); // Создаем новый поток с другой функцией движения>th->Start(); // Стартуем поток

}

}Move()

{(live) // пока поток жив

{= 12 * Math::Cos(fi);= 12 * Math::Sin(fi);(y > 415) y -= 0.27; else y -= 0.05;+= speedX; y += speedY; // движемся(fi < 2 * Math::PI) fi += 0.065; // изменяем угол фиfi = 0;

this->th->Sleep(60); // спим

}

}

};

// Класс формы с объектами

ref class Program : public Form

{^ContForm;< Ship^ > ^ship;^charger;num;numdis;s1, s2;dx, dy;::Threading::Thread ^th;live;

// Констуктор: Program()

{= 1; // стартовое кол-во кораблей

Text = "Objects"; // заголовок окна>Size = System::Drawing::Size(675, 675); // размер окна>FormBorderStyle = System::Windows::Forms::FormBorderStyle::SizableToolWindow;>FormClosed += gcnew FormClosedEventHandler(this, &Program::exit);>Show(); // показываем= Point(200, 50); // позиционируем окно= gcnew ButtonForm(); // подключаем класс формы с кнопками управления>but += gcnew delBut(this, &Program::ButPressed); // привязываем события нажатия кнопок

ship = gcnew array< Ship^ >(10); // Массив из 10 кораблей (макс)

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{[i] = gcnew Ship(i); // Создаем новый объект-корабль и помещаем его в массив

}= gcnew Charger();= true; // буферизация - устраняет мелькание= true; // стартуем= gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &Program::run));>Start();

}

// потоковая функцияrun()

{(live)

{

// перебираем корабли(int i = 0; i < num; i++)

{(Math::Abs(ship[i]->X - charger->X) < 20 && Math::Abs(ship[i]->Y - charger->Y) < 20) // Заправка(!charger->isStopped)

{(ship[i]->fuel <= 89) ship[i]->fuel += 10; else ship[i]->fuel = 99;

}(ship[i]->fuel <= 0) // Если кончается топливо, корабль "исчезает".

{[i]->Stop();[i]->setX = 1000;[i]->setY = 1000 + 50*i;= i;>Invoke(gcnew EventHandler(this, &Program::SetStat)); // Сообщение статуса

//gcnew EventHandler(this, &ButtonForm::onPause);

}(int j = i + 1; j < num; j++)

{(i < j) // Уступает корабль с бОльшим номером

{= j;= i;

}

{= i;= j;

}(Math::Abs(ship[s1]->X - ship[s2]->X) < 20 && Math::Abs(ship[s1]->Y - ship[s2]->Y) < 20)

{[s2]->vstrecha = true; // Встреча началась(!ship[s1]->isStopped && !ship[s2]->isStopped) ship[s2]->Stop();

}if (ship[s2]->vstrecha)

{[s2]->Start(); // Если пропускал, то продолжить движение[s2]->vstrecha = false; // Встреча закончилась;

}

}();::Sleep(31);

}

}

}SetStat(System::Object^ sender, EventArgs^ e)

{>SetStatus(numdis, "Исчез");

};

// перерисовка содержимого окна: virtual void OnPaint(PaintEventArgs^ arg) override

{^grayPen = gcnew Pen(Color::LightGray);^blackPen = gcnew Pen(Color::Black);^blackBrush = gcnew SolidBrush(Color::Black);^whiteBrush = gcnew SolidBrush(Color::White);^greenBrush = gcnew SolidBrush(Color::Lime);::Drawing::Font ^ArialF = gcnew System::Drawing::Font("Arial", 10);>Graphics->FillRectangle(blackBrush,0,0,1280,960); // Фон>Graphics->FillRectangle(whiteBrush, 100, 150, 2, 2); // Звезды>Graphics->DrawEllipse(grayPen, 40, 230, 370, 370); // Орбита Земли>Graphics->DrawEllipse(grayPen, 468, 28, 162, 162); // Орбита Луны>Graphics->FillEllipse(gcnew SolidBrush(Color::DeepSkyBlue), 100, 290, 250, 250); // Земля>Graphics->FillEllipse(gcnew SolidBrush(Color::DarkKhaki), 500, 60, 100, 100); // Луна(int i = 0; i < num; i++) // перебираем корабли

{>Graphics->FillEllipse(greenBrush, ship[i]->X, ship[i]->Y, 16, 16); // корабль>Graphics->DrawEllipse(blackPen, ship[i]->X, ship[i]->Y, 16, 16); // обводим корабль>Graphics->DrawString(ship[i]->id + "", ArialF, blackBrush, ship[i]->X + 4, ship[i]->Y); // номер>Graphics->DrawString(Math::Round(ship[i]->fuel) + "", ArialF, whiteBrush, ship[i]->X - 1, ship[i]->Y - 15);

}>Graphics->FillEllipse(gcnew SolidBrush(Color::DarkRed), charger->X, charger->Y, 16, 16); // заправщик>Graphics->DrawEllipse(blackPen, charger->X, charger->Y, 16, 16); // обводим корабль>Graphics->DrawString("C", ArialF, blackBrush, charger->X + 2, charger->Y); // номер

}

// обработчик событий кнопок формы управленияButPressed(String^ btn, int numship)

{(btn == "add")(num < 10)

{ // если кол-во < 10[num] = gcnew Ship(num); // создаём>SetStatus(num, "В полёте");++;

}

{::Show("Не больше 10!");

}if (btn == "start")

{(int i = 0; i < num; i++)

{(ContForm->IsntDisappeared(i)) ship[i]->Start(); // стартуем все корабли, кроме исчезнувших>SetStatus(i, "В полёте");

}>StartCh();

}if (btn == "stop")

{(int j = 0; j < num; j++)

{[j]->Stop(); // приостанавливаем все корабли

ContForm->SetStatus(j, "Остановлен");

}>Stop();

}if (btn == "fuel") // добавляем 20 единиц топлива

{(ship[numship] != nullptr)

{[numship]->fuel += 20;

if (ship[numship]->fuel > 99) ship[numship]->fuel = 99; // если значение топлива превысит 99, то устанавливается в 99

}

}

}

// событие закрытия окна, завершаем потоки и зыкрываем программу

protected: virtual void OnClosed(EventArgs^ args) override

{(nullptr, nullptr);

}

// обработчик выхода из программы

void exit(Object ^sender, FormClosedEventArgs ^e)

{(int i = 0; i < num; i++)

{[i]->Stop();

}>Stop();>Abort();>Join();::Exit();

}

};

// основная функцияmain(array<System::String ^> ^args)

{::EnableVisualStyles();::SetCompatibleTextRenderingDefault(false);

Application::Run(gcnew Program); // запускаем программу по созданной ссылке0;

}

Похожие работы на - Объектно-ориентированное программирование

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!