Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Медведев_С++_CLI_C#_Java_J#.doc
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
5 Мб
Скачать
☆

Void Change ( )

{

// Выполнить операцию только с одним грузовиком

Monitor::Enter (thls); // Начать критическую секцию

allLoad += partLoad;

Thread::Sleep (tlmePerlod);

Invalidate ();

Monitor:: Exlt (this); // Завершить критическую секцию >

// Перерисовать размещение груза в складе

protected:

virtual void OnPalnt (PaintEventArgs ^e) override

{

UserControl ::OnPaint (e);

e->Graphics->FillRectangie (gcnew SolidBrush (Color::Yellow), 0,

100 - allLoad, CllentSlze.Width, ClientSize.Height);

e->Graphlcs->DrawString (allLoad.ToStrlng (), Font,

gcnew System::Drawing::SolidBrush(Color::Blue),5,10);

>

>>;

C#. Класс поместим в библиотеку csWarehouse.dll с пространством имён

csWarehouse. Для чего при создании проекта на вкладке Templates необходи-

мо выделить Class Library. О создании C# библиотеки см. в приложении 3

"Использование сред разработки" этой книги.

Рассмотрим подробнее класс Warehouse. Поскольку в нашем приложе-

нии будут применены два объекта этого класса, то для идентификации объ-

ектов использован не целочисленный номер, а булевская переменная left,

значение true которой определяет левый склад на прикладном окне, а значе-

ние false - правый. Булевская переменная full принимает значение true, когда

склад заполнен полностью грузом и значение false иначе. Эти данные о скла-

де и его заполнении передаются событием evFromWarehouse, генерируемым

объектом склада в момент возникновения полного опустошения склада. Опи-

сание делегата DelEvFromWarehouse события определяет в качестве списка

параметров обработчиков ссылку к объекту класса WarehouseEventArgs, по-

этому обработчик события, воспользовавшись этой ссылкой и используя

свойства Left и Full ссылаемого объекта, узнает, какой склад оказался опус-

тошённым и подлежит заполнению.

Класс Warehouse наследует класс UserControl с изобилием различных

свойств и функций, позволяющих сделать из него интересный управляющий

элемент, размещённый в окне. Нам понадобится только его свойства

Location, Size, BackColor да возможность перерисовывать его область клиен-

та с помощью функции перерисовки OnPaint().

Параметры конструктора Warehouse устанавливают местоположение и

O o r m / W P U U A i ^ T L Л Г П в TlO

J U I ^ j / l V V l i l l W W l W w i w l u ^ u .

Интерфейсные функции Put() и Get() выгружают или загружают грузовик,

используя для этого внутреннюю функцию Change(). При этом груз allLoad,

содержащийся в складе, либо увеличивается, либо уменьшается на порцию

partLoad. В случае, когда склад не дозволяет выгрузить груз из грузовика в

виду переполнения склада или не имеет возможность загрузить грузовик из-

за отсутствия груза, функции Put() и Get() возвращают значение false. Также

значение false возвращается при попытке выгрузиться пустому грузовику и

загрузится уже заполненному грузовику. Хотя последние случаи маловеро-

ятны, для надёжности программы необходимо учитывать все возможные си-

туации - программа должна функционировать и при неправильных исходных

данных. При полном опустошении склада генерируется событие evFrom-

Warehouse, извещающее о необходимости смены направления перевозки гру-

за из складов. Обработчик, подписавшийся на это событие, обязан уведо-

мить все грузовики о необходимости смены направления перевозки груза.

Для этого применяется булевская переменная leftRight и свойство LeftRight

каждого грузовика. Их значение, равное true, определяет движение слева на-

право, а значение false - справа налево.

Чтобы сделать выгрузку или загрузку груза доступной только для одного

грузовика, функция Change() реализована как критическая секция с примене-

нием функций Enter() и Exit() монитора класса Monitor (или оператора lock).

Функция Invalidate(), вызываемая в теле функции Change(), инициирует

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

порции partLoad груза. При этом закрашенная желтым цветом часть прямо-

угольника склада увеличивается или уменьшается, динамически показывая

текущую загруженность склада грузом.

Java и J#. Класс Warehouse поместим в пакет cjWarehouse.dll. Для чего при

создании проекта в системе разработки Eclipse необходимо создать класс без

функции main(). О создании такого пакета см. в приложении 3 "Использова-

ние сред разработки" в конце книги.

Программа на языке Java отличается, прежде всего, появлением класса

beWatched, наследующего интерфейс Observable. Наследование интерфейса

Observable указывает, что объекты класса beWatched являются наблюдаемы-

ми объектами, то есть объектами, которые уведомляют о чём-либо другие

объекты - обозреватели. Необходимость в создании наблюдаемого (уведом-

ляющего) объекта этого класса в объекте склада возникла по простой причи-

не: класс Warehouse склада уже наследует класс Panel и поэтому не может

наследовать второй класс Observable, чтобы уведомить об опустошении

склада. По этой причине в классе Warehouse создаётся объект класса be-

Watched, и на него будет подписан обозреватель, содержащий обработчик,

реагирующий на уведомление от этого объекта. Для генерирования уведом-

ления достаточно вызвать функцию notifyObs() этого объекта, которая вызы-

вает, в свою очередь, стандартные функции setChanged() и

notifyObservers(arg), уведомляющие подписавшегося обозревателя. При этом

обработчику обозревателя передаётся объект arg типа WarehcussEvsntArgs

содержащий идентификатор склада и информацию о заполнении склада.

В функциях Put() и Get() на языке Java вызов делегата языка C# заменён вы-

зовом функции notifyObs() наблюдаемого объекта, содержащей в качестве

аргумента объект wA типа WarehouseEventArgs, включающий данные о

складе.

Критическая секция функции change() реализована с помощью оператора

synchronized. Выполнение функции change() изменяет содержимое склада и,

вызывая функцию repaint(), заставляет перерисовываться панель, которой

представлен склад в прикладном окне.

Приложение, представленное в примере 11.4.1.2, иллюстрирует работу

двух объектов класса Warehouse. Специальный поток thr приложения осуще-

ствляет загрузку в склады и выгрузку из складов груза, используя интер-

фейсные функции Get() и Put() класса Warehouse и признак направленности

leftRight, значение которого меняются событиями из объектов класса

Warehouse.

Пример 11.4.1.2. Приложения csTestWarehouse и cjTestWarehouse.

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

// C# File csTestWarehouse

// Подключить системные библиотеки System.Drawing.dll и

// System.Windows.Forms.dll

// Подключить разработанную библиотеку csWarehouse

using System;

using System.Drawing;

using System.Threading;

using System.Windows.Forms;

using csWarehouse;

namespace csTestWarehouse

{

class TestWarehouse: Form

{

Warehouse leftWH, rlghtWH; // Ссылки на объекты

// компонента Warehouse

bool leftRlght; // Признак направления перемещения грузовиков

bool llfe; // Признак жизни потока управления загрузкой

// и выгрузкой складов

Thread thr; // Ссылка на поток управления загрузкой

// и выгрузкой складов

public TestWarehouse ( )

{

// Создать объект левого склада

leftWH= new Warehouse (true, true);

leftWH.Location= new Polnt (10, 10);

leftWH.SIze= new Slze (30, 100);

leftWH.BackColor= Color.White;

leftWH.evFromWarehouse+ =

new DelEvFromWarehouse (WarehouseHandler);

t'nis,Controis.Add (leftWH);

leftWH.Show ( );

// Создать объект правого склада

rlghtWH= new Warehouse (false, false);

rightWH.Location= new Point (100, 10);

rlghtWH.SIze= new Slze (30, 100);

rightWH,BackColor= Color.White;

rightWH.evFromWarehouse+=

new DelEvFromWarehouse (WarehouseHandler);

thls.Controls.Add (rightWH);

rightWH,Show ( );

// Создать и запустить поток управления загрузкой

// и выгрузкой складов

leftRight= true;

life= true;

thr= new Thread(new ThreadStart (Go));

thr.Start ( );

}

// Обработать событие evFromWarehouse

vold WarehouseHandler (object ob, WarehouseEventArgs arg)

<

// Выдать информацию о направлении перемещения и

// о складе, объект которого сгенерировал событие

Console.Write("event evFromWarehouse leftRight=" +

leftRight);

if (arg,Left)

Console.Write("CKnafl leftWH ");

else

Console.Wrlte(" Склад rightWH ");

if(arg.Full)

Console.WriteLine(" полный");

else

Console.WriteLine(" пустой");

Console.WriteLine( );

// Изменить направление перемещения грузовиков

if(arg.Left && arg.Full)

leftRight= true;

if (larg.Left &&arg.Full)

leftRight= false;

// Обеспечить загрузку груза в склады и

// выгрузку груза иэ складов

vold Go ( )

{

while (life)

{

lf (leftRight) {leftWH.Get (false ); rightWH.Put(true);}

else {leftWH.Put (true ); rightWH.Get (false );>

>

>

// Завершить поток управления загрузкой

// и выгрузкой складов

vold Finish ( )

{

life= false;

thrJo!n ( );

>

static void Main ( )

{

// Создать объект прикладного окна

TestWarehouse testWH= new TestWarehouse ();

// Запустить приложение с прикладным окном

Appllcation.Run (testWH);

// Завершить поток управления загрузкой

// и выгрузкой складов

testWH.Finish ();

>

>

/>*

Result:

event evFromWarehouse leftRight= True Склад leftWH пустой

event evFromWarehouse leftRight= False Склад rlghtWH полный

event evFromWarehouse leftRight= False Склад leftWH полный

event evFromWarehouse leftRight= True Склад leftWH пустой

* / "

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

// Java и J#. File cjTestWarehouse

package cjTestWarehouse; // Класс Warehouse и отладка