- •Введение к заданиям Основные термины, используемые в дисциплинах
- •Объекты, классы и язык uml
- •Цели задачи заданий
- •Требования к выполнению заданий
- •Оформление результатов
- •4. Содержание разделов пояснительной записки
- •5. Оформление результатов
- •Список литературы
- •Приложение 1. Пример оформления результатов
- •Содержание
- •5.1. Первый этап. Разработка компонента Warehouse
- •5.2. Второй этап. Разработка компонентов ContrlRegion и Lorry
- •5.3. Третий этап. Разработка приложения csLorryAndWarehouse
- •1. Задание
- •Уточнение задания
- •3. Описание разрабатываемой программы с точки зрения пользователя
- •4. Описание разрабатываемой программы с точки зрения программиста
- •4.1. Объектное представление программы
- •4.2. События, потоки и ресурсы
- •5. Поэтапная разработка программы
- •5.1. Первый этап. Разработка компонента Warehouse
- •5.2. Второй этап. Разработка компонентов ContrlRegion и Lorry
- •5.3. Третий этап. Разработка приложения csLorryAndWarehouse
- •6. Описание проблем, возникших при разработке программной системы.
- •7. Список используемой литературы
- •10. Разработка многокомпонентной программы с удалённым объектом
- •10.1. Удалённый компонент RemObj
- •10.2. Сервер csLorryAndWarhousesServer
- •10.3. Клиент csLorryAndWarhousesClient
5. Поэтапная разработка программы
В результате объектного анализа программы выявилась необходимость разработки следующих классов:
- класс LorryAndWarehouse - класс объекта, представляющего функционирование реализуемой модели в окне;
- компонент Warehouse, объектами которого являются склады;
- компонент Lorry, объектами которого являются грузовики;
- класс ContrlRegion, объектом которого является зона контроля.
5.1. Первый этап. Разработка компонента Warehouse
Интерфейс компонента Warehouse содержит функции, обеспечивающие выгрузку в склад и загрузку из склада в грузовик груза, и событие, сообщающее объектам компонента Lorry о необходимости изменения ими направления движения из-за переполнения или опустошения склада.
Рис. Диаграмма классов компонента Warehouse
Интерфейс компонента Warehouse включает функции Put() и Get():
void Put ( );
Выгрузить груз из грузовика в склад.
void Get ( );
Загрузить груз в грузовик из склада.
В интерфейс входит событие, сигнализирующее грузовикам, движущимся к этому складу с грузом о необходимости смены направления движения. Данные события содержаться в объекте класса WarehouseEventArgs и включают свойства Full и Left, определяющие, возникло ли переполнение или опустошение склада, и в каком складе – левом или правом.
Делегат события определим так:
public delegate void DelEvFromWarehouse (object sender, WarehouseEventArgs
args);
А событие как:
event DelEvFromWarehouse evFromWarehouse;
Для простоты реализации фиксируется максимальная вместимость склада allLoad числом 100. Груз размером 10 загружается в склад или выгружается из склада равными пятью порциями partLoad через 100 мс. (timePeriod), чтобы отобразить продолжительность обслуживания грузовика складом постепенным заполнением прямоугольника, представляющего склад на экране, и обусловить необходимость синхронизации загрузки и разгрузки разных грузовиков.
Функции Put() и Get() осуществляют продолжительную загрузку и выгрузку грузовиков, используя потоки. Применение рабочих потоков способствует параллельному выполнению другого множества потоков, используемых объектами компонентов, то есть многопоточному функционированию программы.
Компонент Warehouse, написанный на языке C#, наследует интерфейс IWarehouse и класс UserControl, включающий в компонент возможность перерисовки собственной области клиента. Приложение csTestWarehouse позволяет убедиться в работоспособности компонента Warehouse и отладить компонент. Компонент Warehouse размещён в библиотеке csWarehouse с пространством имён csWarehouseDll.
Компонент Warehouse.
///////////////
// C# компонент Warehouse
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;
namespace csWarehouseDll
{
// Класс данных события evFromWarehouse
public class WarehouseEventArgs: EventArgs
{
private bool left; // Признак идентификации склада
private bool full; // Признак заполненности склада
public WarehouseEventArgs (bool left, bool full)
{this.left= left; this.full= full;}
// Свойство заполнения склада
public bool Full
{get {return full;}}
// Свойство идентификации склада
public bool Left
{get {return left;}}
}
// Делегат события о переполнении и опустошении склада
public delegate void DelEvFromWarehouse (object sender,
WarehouseEventArgs args);
// Интерфейс склада
public interface IWarehouse
{
void Put ( ); // Поместить груз в склад
void Get ( ); // Получить груз из склада
event DelEvFromWarehouse evFromWarehouse; // Ссылка на объект
// события о переполнении и опустошении склада
}
// Компонент склада
public class Warehouse: UserControl, IWarehouse
{
bool left; // Признак идентификации склада
int allLoad= 100; // Текущий размер груза в складе
int PartLoad= 10; // Размер груза грузовика
int partLoad; // Разгружаемая или загружаемая порция груза
int numParts= 5; // Количество порций
int timePeriod= 100; // Время разгрузки или загрузки
// порции груза
Thread thr; // Ссылка на объект потока
public event DelEvFromWarehouse evFromWarehouse; // Ссылка
// на объект события о переполнении и опустошении склада
// Конструктор
public Warehouse (bool left, bool full)
{
this.left= left;
if (!full) allLoad= 0; // Склад пуст
}
// Разгрузить груз в склад
public void Put ( )
{
if (((100 - allLoad) < PartLoad) && (evFromWarehouse != null)) {
// Недостаточно места в складе для разгрузки грузовика
WarehouseEventArgs wH= new WarehouseEventArgs (left,
true);
evFromWarehouse (this, wH); // Сгенерировать событие
return;
}
// Разгрузить грузовик и увеличить порциями груз склада
// с помощью потока
partLoad= PartLoad; // Определить выгрузку
// Создать поток выгрузки склада
thr= new Thread (new ThreadStart (Change));
thr.Start ( ); // Стартовать поток
thr.Join ( ); // Подождать завершения потока
}
// Получить груз из склада
public void Get ( )
{
if (((allLoad) < PartLoad) && (evFromWarehouse != null))
{
// Недостаточно груза в складе для загрузки грузовика
WarehouseEventArgs wH= new WarehouseEventArgs
(left, false);
evFromWarehouse (this, wH); // Сгенерировать событие
return;
}
// Загрузить грузовик и уменьшить порциями груз склада
// с помощью потока
partLoad= -PartLoad; // Определить выгрузку
// Создать поток загрузки склада
thr= new Thread (new ThreadStart (Change));
thr.Start ( ); // Стартовать поток
thr.Join ( ); // Подождать завершения потока
}
// Разгрузить или загрузить груз порциями
protected void Change ( )
{
// Выполнить операцию только с одним грузовиком
Monitor.Enter (this); // Начать критическую секцию
for (int i= 0; i < numParts; i++)
if ((allLoad >= 0 && partLoad < 0) ||
(allLoad <= 100 && partLoad > 0))
{
allLoad += partLoad/numParts;
Thread.Sleep (timePeriod);
Invalidate ( );
}
Monitor.Exit (this); // Завершить критическую секцию
}
// Перерисовать размещение груза в складе
protected override void OnPaint (PaintEventArgs e)
{
base.OnPaint (e);
e.Graphics.FillRectangle (new SolidBrush (Color.Yellow), 0,
100 - allLoad, ClientSize.Width, ClientSize.Height);
e.Graphics.DrawString (allLoad.ToString ( ), Font,
new System.Drawing.SolidBrush (Color.Blue), 5, 10);
}
}
}
Приложение csTestWarehouse.
///////////////
// C#
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;
using csWarehouseDll;
namespace csTestWarehouse
{ class TestWarehouse: Form
{
Warehouse leftWH, rightWH; // Ссылки на объекты
// компонента Warehouse
bool leftRight; // Признак направления перемещения грузовиков
bool life; // Признак жизни потока управления загрузкой
// и выгрузкой складов
Thread thr; // Ссылка на поток управления загрузкой
// и выгрузкой складов
public TestWarehouse ( )
{
// Создать объект левого склада
leftWH= new Warehouse (true, true);
leftWH.Location= new Point (10, 10);
leftWH.Size= new Size (30, 100);
leftWH.BackColor= Color.White;
leftWH.evFromWarehouse+=
new DelEvFromWarehouse (WarehouseHandler);
this.Controls.Add (leftWH);
leftWH.Show ( );
// Создать объект правого склада
rightWH= new Warehouse (false, false);
rightWH.Location= new Point (100, 10);
rightWH.Size= new Size (30, 100);
rightWH.BackColor= Color.White;
rightWH.evFromWarehouse+=
new DelEvFromWarehouse (WarehouseHandler);
this.Controls.Add (rightWH);
rightWH.Show ( );
// Создать и запустить поток управления загрузкой
// и выгрузкой складов
leftRight= true;
life= true;
thr= new Thread(new ThreadStart (Go));
thr.Start ( );
}
// Обработать событие evFromWarehouse
void WarehouseHandler (object ob, WarehouseEventArgs arg)
{
// Выдать информацию о направлении перемещения и
// о складе, объект которого сгенерировал событие
Console.Write("event evFromWarehouse leftRight=" +
leftRight);
if (arg.Left)
Console.Write(" Компонент leftWH ");
else
Console.Write(" Компонент rightWH ");
if (arg.Full)
Console.WriteLine(" полный");
else
Console.WriteLine(" пустой");
Console.WriteLine( );
// Изменить направление перемещения грузовиков
if( (arg.Left && arg.Full)||
(!arg.Left && !arg.Full))
leftRight= true;
if ((arg.Left && !arg.Full)||
(!arg.Left && arg.Full))
leftRight= false;
}
// Обеспечить загрузку груза в склады и
// выгрузку груза из складов
void Go ( )
{
while (life)
{ if (leftRight) {leftWH.Get ( ); rightWH.Put ( );}
else {leftWH.Put ( ); rightWH.Get ( );}
}
}
// Завершить поток управления загрузкой
// и выгрузкой складов
void Finish ( )
{
life= false;
thr.Join ( );
}
static void Main ( )
{
// Создать объект прикладного окна
TestWarehouse testWH= new TestWarehouse ( );
// Запустить приложение с прикладным окном
Application.Run (testWH);
// Завершить поток управления загрузкой
// и выгрузкой складов
testWH.Finish ( );
}
}
}
/*
Result:
event evFromWarehouse leftRight= True Компонент leftWH пустой
event evFromWarehouse leftRight= False Компонент rightWH полный
event evFromWarehouse leftRight= False Компонент leftWH полный
event evFromWarehouse leftRight= True Компонент leftWH пустой
. . .
*/
Рис. Результат работы приложения csTestWarehouse.