- •Введение к заданиям Основные термины, используемые в дисциплинах
- •Объекты, классы и язык 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
10.2. Сервер csLorryAndWarhousesServer
Приложение-сервер создаёт объект удаленного компонента, объект канала
и осуществляет маршализацию удалённого объекта, используя объект удаленного компонента и классы HttpChannel, ChannelServices и RemotingServices. Диаграмма классов сервера csLorryAndWarhousesServer представлена ниже. После запуска приложения появляется прикладное окно сервера (фактически являющееся окном удалённого объекта).
Рис. Диаграмма классов сервера csLorryAndWarhousesServer
Сервер csLorryAndWarhousesServer
/////////////////////////
// C# File csLorryAndWarehouseServer Сервер
using System;
using System.Windows.Forms;
using csLorryAndWarehouseRemotingDll;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace csLorryAndWarehouseServer
{
class LorryAndWarhouses
{
// Основная функция
static void Main ( )
{
// Создать удалённый объект компонента RemObj
csLorryAndWarehouseRemotingDll.RemObj remObj;
remObj= new RemObj ( );
// Создать и зарегистрировать канал
HttpChannel httpChannel;
try
{
httpChannel= new HttpChannel (8080);
ChannelServices.RegisterChannel (httpChannel);
}
catch(Exception e)
{
Console.WriteLine (e.Message);
return;
}
// Маршализовать удалённый объект компонента
RemotingServices.Marshal (remObj, "RemoteObject");
// Создать окно удалённого объекта компонента RemObj
Application.Run (remObj);
}
}
}
10.3. Клиент csLorryAndWarhousesClient
Приложение-клиент csLorryAndWarhousesClient, создав прокси удалённого компонента RemObj, кнопки и элемент списка, использует их для управления моделью, функционирование которой представлено в прикладном окне сервера.
Рис. Диаграмма классов клиента csLorryAndWarhousesClient
Для обеспечения связи с удалённм объектом применены классы HttpChannel, ChannelServices и Activator.
Клиент csLorryAndWarhousesClient
/////////////////////////
// C# File csLorryAndWarehouseClient Клиент
// Приложение-клиент с с управляющими
// элементами
//
using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using csLorryAndWarehouseRemotingDll;
//-----
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace csLorryAndWarehouseClient
{
class LorryAndWarehouses: Form
{
csLorryAndWarehouseRemotingDll.IRemObj iRemObj;
Button butRun, butStop; // Ссылки на интерфейсные кнопки
Button butAdd, butDel; // Ссылки на интерфейсные кнопки
ListBox listBox; // Список номеров грузовиков
// Конструктор
LorryAndWarehouses ( )
{
this.Text= "Client";
this.ClientSize= new Size(350, 50);
// Создать кнопки
butRun= new Button ( ); // Создать кнопку пуска
butRun.Location= new Point (10, 5);
butRun.Size= new Size (45, 20);
butRun.Text= "Run";
butRun.BackColor= Color.LightGray;
butRun.Click += new EventHandler (But_Run);
this.Controls.Add (butRun);
//-----
butStop= new Button ( ); // Создать кнопку останова
butStop.Location= new Point (60, 5);
butStop.Size= new Size (45, 20);
butStop.Text= "Stop";
butStop.BackColor= Color.LightGray;
butStop.Click += new EventHandler (But_Stop);
this.Controls.Add (butStop);
//-----
butAdd= new Button ( ); // Создать кнопку добавления
// компонента
butAdd.Location= new Point (110,5);
butAdd.Size= new Size (65, 20);
butAdd.Text= "Add";
butAdd.BackColor= Color.LightGray;
butAdd.Click += new EventHandler (But_Add);
this.Controls.Add (butAdd);
butDel= new Button ( ); // Создать кнопку удаления
// компонента
butDel.Location= new Point (185,5);
butDel.Size= new Size (65, 20);
butDel.Text= "Delete";
butDel.BackColor= Color.LightGray;
butDel.Click += new EventHandler (But_Del);
this.Controls.Add (butDel);
//
listBox= new ListBox ( ); // Создать элемент списка
listBox.Location= new Point (265, 5);
listBox.Size= new System.Drawing.Size (60, 20);
this.Controls.Add (listBox);
this.Show ( );
// Создать канал и зарегистрировать
HttpChannel httpChannel= new HttpChannel (0);
ChannelServices.RegisterChannel (httpChannel);
iRemObj= (IRemObj) Activator.GetObject (
typeof (csLorryAndWarehouseRemotingDll.IRemObj),
"http://localhost:8080/RemoteObject");
}
// Обработать нажатие кнопки пуска
private void But_Run (object o, EventArgs e)
{
iRemObj.RunLorriers ( );
}
// Обработать нажатие кнопки останова
private void But_Stop (object o, EventArgs e )
{
iRemObj.StopLorriers ( );
}
// Обработать нажатие кнопки добавления грузовика
private void But_Add (object o, EventArgs e)
{
iRemObj.AddLorry ( );
iRemObj.ShowComponents ( );
ArrayList aL= new ArrayList ( );
aL= iRemObj.GetNumLorries( );
listBox.Items.Clear ( );
for (int i= 0; i < aL.Count; i++)
listBox.Items.Add (aL[i]);
}
// Обработать нажатие кнопки удаления грузовика
private void But_Del (object o, EventArgs e )
{
if (listBox.SelectedIndex == -1)
{
MessageBox.Show
("Выберете номер удаляемого грузовика в"
+ "\nэлементе списка перед нажатием кнопки");
}
else
{
int numSel= (int) listBox.SelectedItem;
listBox.Items.Remove (numSel);
iRemObj.RemoveLorry (numSel);
ArrayList aL= new ArrayList ( );
aL= iRemObj.GetNumLorries ( );
listBox.Items.Clear ( );
for (int i= 0; i < aL.Count; i++)
listBox.Items.Add (aL[i]);
iRemObj.ShowComponents ( );
}
}
// Обработать кнопку закрытия окна
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
iRemObj.RemoveAllLorries ( );
}
// Основная функция
static void Main ( )
{
Application.Run (new LorryAndWarehouses ( ));
}
}
}
На рисунке представлены прикладные окна сервера и клиента.
Рис. Прикладные окна сервера и клиента
Приложение 2. cjLorryAndWarehouse- приложение на языке Java(J#)
///////////////
// Java
// Приложение с компонентами Lorry, Warehouse, ConrlRegion
// и с управляющими элементами
//
import java.awt.*;
import java.util.*;
import java.awt.event.*;
// Класс данных события
public class WarehouseEventArgs
{
private boolean left; // Признак идентификации склада
private boolean full; // Признак заполнения склада
// Конструктор
public WarehouseEventArgs (boolean left, boolean full)
{
this.left= left; this.full= full;
}
// Свойство заполнения склада
public boolean getFull ( ) {return full;}
// Свойство идентификации склада
public boolean getLeft ( ) {return left;}
}
class beWatched extends Observable // Класс наблюдаемого объекта
{
// Конструктор
public beWatched ( ) { }
void notifyObs (WarehouseEventArgs arg)
{ setChanged ( ); notifyObservers (arg);}
}
// Класс склада
public class Warehouse extends Panel
{
boolean left; // Признак идентификации склада
int allLoad; // Текущий размер груза в складе
int PartLoad= 10; // Размер груза грузовика
int partLoad; // Получаемая или помещаемая порция груза
int timePeriod= 100; // Время получения или помещения груза
public beWatched bW; // Ссылка на вспомогательный наблюдаемый
// объект
// Конструктор
public Warehouse (boolean left, boolean full)
{
allLoad= 100;
this.left= left;
if (!full) allLoad= 0; // Склад пуст
bW= new beWatched (); // Наблюдаемый объект склада
}
// Поместить груз в склад
synchronized public boolean Put (boolean full )
{
if (!full) return false;
if (allLoad >= 100) return false;
// Выгрузить грузовик и увеличить груз склада
partLoad= PartLoad; // Определить выгрузку
change ( );
return true;
}
// Получить груз из склада
synchronized public boolean Get (boolean full )
{
if (full) return false;
if (((allLoad) < PartLoad))
{
// Недостаточно груза в складе для загрузки грузовика
WarehouseEventArgs wA= new WarehouseEventArgs
(left, false);
bW.notifyObs (wA); // Уведомить обозревателя
return false;
}
// Загрузить грузовик и уменьшить груз склада
partLoad= -PartLoad; // Определить выгрузку
change ( );
return true;
}
// Поместить или получить груз
public void change ( )
{
// Выполнить операцию только с одним грузовиком
synchronized (this) // Критическая секция
{
allLoad += partLoad;
try
{
Thread.sleep (timePeriod);
}
catch (InterruptedException e) { }
repaint ( );
}
}
// Перерисовать размещение груза в складе
public void paint (Graphics g)
{
g.setColor (Color.yellow);
g.drawRect (0, 0, this.getSize().width, this.getSize().height);
g.fillRect (0, this.getSize().height - allLoad, this.getSize().width,
this.getSize().height);
g.setColor (Color.black);
g.drawString (Integer.toString (allLoad), 5, 30);
}
}
// Класс ContrlRegion
public class ContrlRegion extends Panel
{
// Проконтролировать грузовик
public void Work ( )
{
try
{
Thread.sleep (1000);
}
catch (InterruptedException e){}
}
}
// Класс Lorry
public class Lorry implements Runnable
{
public int number; // Номер грузовика
public Point p; // Координаты объекта грузовика
int dX; // Приращение координаты Х
public boolean leftRight; // Направление перемещения груза
ContrlRegion region; // Ссылка на зону контроля
boolean inContrl; // Признак нахождения в зоне контроля
boolean life; // Признак жизни потока
boolean running; // Признак выполнения потока
Thread thr; // Ссылка на объект потока
int timePeriod= 100; // Временной интервал перемещения
Warehouse leftWH; // Ссылка на левый склад
Warehouse rightWH; // Ссылка на правый склад
Rectangle rect;
boolean full;
// Конструктор
public Lorry (int Number, int Y, int DX, Warehouse LeftWH,
Warehouse RightWH, ContrlRegion Region)
{
number= Number; dX= -DX; leftRight= true;
leftWH= LeftWH; rightWH= RightWH; full= false;
region= Region; inContrl= false; p= new Point ( );
p.x= leftWH.getLocation().x+leftWH.WIDTH + 50; p.y= Y;
rect= new Rectangle (region.getLocation().x,
region.getLocation().y, region.getSize().width,
region.getSize().height);
running= true; life= true;
// Создать объект потока
thr= new Thread (this);
thr.start ( );
}
// Свойство Number
public int getNumber ( ) {return number;}
// Свойство Point
public Point getPoint ( ) {return p;}
// Свойство LeftRight
public boolean getLeftRight ( ){return leftRight;}
public void setLeftRight (boolean LeftRight) {this.leftRight= LeftRight;}
// Свойство Full
public boolean getFull ( ){return full;}
// Завершить поток
public void Finish ( ) {life= false;};
public void Stop ( ) // Приостановить поток
{
running= false;
}
synchronized public void Run ( ) // Возобновить поток
{
running= true;
notify();
}
// Потоковая функция
public void run ( )
{
while (life)
{
try
{
synchronized (this)
{
if(!running)
wait ( ); // Подождать
}
}
catch(InterruptedException e) { }
// Грузовик достиг справа левый склад
if (p.x <= leftWH.getLocation().x+leftWH.WIDTH)
{
//System.out.println ("the left warehouse");
if (leftRight) // Пересылка слева направо
{if(leftWH.Get(full)) full= true;} // Загрузить груз
else
{if(leftWH.Put(full)) full= false;} // Выгрузить груз
dX= -dX;
}
// Грузовик достиг слева правый склад
if (p.x >= rightWH.getLocation().x)
{
//System.out.println ("the right warehouse");
if (leftRight) // Пересылка слева направо
{if(rightWH.Put(full)) full= false;} // Выгрузить груз
else
{if(rightWH.Get(full)) full= true;} // Загрузить груз
dX= -dX;
}
// Обслужить в зоне контроля
// Вошли в зону контроля
if (rect.contains (p) && !inContrl) // Вошли в зону
{
//System.out.println ("enter in the region");
inContrl= true;
synchronized(region)
{
region.Work ( );
}
}
if (!rect.contains (p) && inContrl) // Вышли из зоны
{
//System.out.println ("leave the region");
inContrl= false;
}
try
{
Thread.sleep (timePeriod);
}
catch (InterruptedException e){}
p.x += dX;
}
}
}
class LorryAndWarehouses extends Frame implements Runnable, Observer
{
Lorry lorry; // Ссылка на объект грузовика
Warehouse leftWH; // Ссылка на объект левого склада
Warehouse rightWH; // Ссылка на объект правого склада
ContrlRegion region; // Ссылка на объект зоны контроля
Button butRun, butStop; // Ссылки на интерфейсные кнопки
Button butAdd, butDel; // Ссылки на интерфейсные кнопки
Choice choice; // Ссылка на элемент списока
Thread thread; // Ссылка на объект потока перерисовки
boolean life; // Признак жизни потока перерисовки
int numLorry= 0; // Номер грузовика
boolean leftRight; // Признак направления перемещения грузовиков
int Y= 20; // Координата Y пути грузовика
Random rand; // Ссылка на случайное число
ArrayList aL; // Ссылка на список объектов грузовиков
// Конструктор
LorryAndWarehouses ( )
{
this.setTitle ("Test"); // Установить заголовок окна
this.setSize (350, 180); // Установить размер окна
this.setLayout (null); // Установить отсутствие менеджера расстановки
this.setBackground (Color.lightGray);
aL= new ArrayList ( ); // Создать объект списка грузовиков
rand= new Random ( ); // Создать случайное число
leftRight= true; // Установить направление "слева направо"
// Создать кнопки
// Создать кнопку "Add" добавления шара
butAdd= new Button ("Add"); // Создать объект кнопки
butAdd.setLocation (240,85); // Разместить в окне
butAdd.setSize (65, 20); // Установить размер кнопки
butAdd.setBackground (Color.lightGray);
this.add (butAdd); // Добавить кнопку в коллекцию окна
// Подписать обработчик на событие кнопки ""Add"
butAdd.addActionListener (new ActionListener ( )
{
public void actionPerformed (ActionEvent aE)
{
numLorry++;
Y += 20;
int dX = rand.nextInt (5) + 5;
if (leftRight) dX= dX;
else dX= -dX;
// Создать объект грузовика
lorry= new Lorry (numLorry, Y, dX, leftWH, rightWH,
region);
aL.add (lorry); // Включить объект в список грузовиков
// Добавить номер грузовика в элемент списка номеров
choice.addItem (Integer.toString(numLorry));
}
});
// Создать кнопку "Del" удаления
butDel= new Button ("Del"); // Создать объект кнопки
butDel.setLocation (240,115); // Разместить в окне
butDel.setSize (65, 20); // Установить размер кнопки
butDel.setBackground (Color.lightGray);
this.add (butDel); // Добавить кнопку в коллекцию окна
// Подписать обработчик на событие кнопки "Del"
butDel.addActionListener (new ActionListener ( )
{
public void actionPerformed (ActionEvent aE)
{
// Если есть элементы в списке, то удалить грузовик с
// наименьшим номером или выбранным номером из
// списка
if(choice.getItemCount()!=0)
{
String s= choice.getSelectedItem();
int num= Integer.parseInt(s);
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
if (lorry.number == num)
{
lorry.Finish ( );
aL.remove (i);
choice.remove(s);
return;
}
}
}
}
});
// Создать кнопку "Run" пуска
butRun= new Button ("Run"); // Создать объект кнопки
butRun.setLocation (240,25); // Разместить в окне
butRun.setSize (45, 20); // Установить размер кнопки
butRun.setBackground (Color.lightGray);
this.add (butRun); // Добавить кнопку в коллекцию окна
// Подписать обработчик на событие кнопки "Run"
butRun.addActionListener (new ActionListener ( )
{
public void actionPerformed (ActionEvent aE)
{
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
lorry.Run ( );
}
}
});
// Создать кнопку "Stop" останова
butStop= new Button ("Stop"); // Создать объект кнопки
butStop.setLocation (240,55); // Разместить в окне
butStop.setSize (45, 20); // Установить размер кнопки
butStop.setBackground (Color.lightGray);
this.add (butStop); // Добавить кнопку в коллекцию окна
// Подписать обработчик на событие кнопки "Stop"
butStop.addActionListener (new ActionListener ( )
{
public void actionPerformed (ActionEvent aE)
{
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
lorry.Stop ( );
}
}
});
// Создать элемент списка номеров грузовиков
choice= new Choice ( ); // Создать объект элемента списка
choice.setLocation (240, 145); // Разместить в окне
choice.setSize (60, 20); // Установить размер элемента
this.add (choice); // Добавить элемент в коллекцию окна
// Создать склады
// Создать объект leftWH левого склада
leftWH= new Warehouse (true, true); // Создать объект склада
leftWH.setLocation (10, 10); // Разместить в окне
leftWH.setSize (30, 100); // Установить размер склада
leftWH.setBackground (Color.white);
leftWH.bW.addObserver(this);
this.add (leftWH); // Добавить склад в коллекцию окна
leftWH.show ( );
// Создать объект rightWH правого склада
rightWH= new Warehouse (false, false); // Создать объект склада
rightWH.setLocation (200, 10); // Разместить в окне
rightWH.setSize (30, 100); // Установить размер склада
rightWH.setBackground (Color.white);
rightWH.bW.addObserver(this);
this.add (rightWH); // Добавить склад в коллекцию окна
rightWH.show ( );
// Создать область region контроля
region= new ContrlRegion ( ); // Создать объект области контроля
region.setLocation (100, 0); // Разместить в окне
region.setSize (30, 200); // Установить размер области
region.setBackground (Color.green);
this.add (region); // Добавить область в коллекцию окна
// Создать поток thread перерисовки и запустить его
life= true;
thread= new Thread (this,"controlThread");
thread.start();
}
// Потоковая функция run перерисовки
public void run ( )
{
while (life)
{
repaint ( ); // Перерисовать окно
try
{
Thread.sleep (150);
}
catch (InterruptedException e){}
}
}
// Завершить поток перерисовки
public void Finish ( )
{
life= false;
}
// Завершить все потоки при закрытии прикладного окна
public boolean handleEvent (Event e)
{
if (e.id == Event.WINDOW_DESTROY)
{
// Завершить потоки грузовиков
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
lorry.Finish ( );
}
// Завершить поток перерисовки
Finish ( );
// Завершить основной поток
System.exit(0);
}
return (super.handleEvent(e));
}
// Перерисовать область клиента прикладного окна
public void paint (Graphics g)
{
// Нарисовать каждый грузовик с номером
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
g.setColor (Color.blue);
g.drawOval (lorry.p.x - 10, lorry.p.y - 10, 20, 20);
if(lorry.getFull())
g.fillOval (lorry.p.x - 10, lorry.p.y - 10, 20, 20);
if(lorry.getLeftRight()) g.setColor(Color.red);
else g.setColor(Color.green);
g.drawString (Integer.toString(lorry.number), lorry.p.x + 10,
lorry.p.y + 10);
}
}
// обработать уведомление склада
public void update (Observable obs, Object args)
{
WarehouseEventArgs arg=(WarehouseEventArgs) args;
// Изменить направление перемещения грузовиков
if(arg.getLeft() && !arg.getFull())
leftRight= false;
if (!arg.getLeft() && !arg.getFull())
leftRight= true;
// Завершить потоки грузовиков
for (int i= 0; i<aL.size(); i++)
{
Lorry lorry= (Lorry) aL.get(i);
lorry.setLeftRight (leftRight);
}
// Выдать информацию о направлении перемещения и
// о складе, объект которого сгенерировал событие
//Console.Write("event evFromWarehouse leftRight=" +
// leftRight);
if (arg.getLeft())
System.out.print("Склад leftWH ");
else
System.out.print(" Склад rightWH ");
if (arg.getFull())
System.out.println(" полный");
else
System.out.println(" пустой");
}
// Выполнить основной поток приложения
public static void main ( )
{
LorryAndWarehouses laWH= new LorryAndWarehouses ( );
laWH.show ( );
}
}