- •Содержательная (исходная) постановка задачи. Вариант 2.1.33
- •Проектные решения
- •Объектно-ориентированная модель задачи.
- •Контракты классов.
- •Проектирование конструкторов и деструкторов классов.
- •Разработка методики тестирования классов и тестовых наборов данных.
- •Сценарий диалога с пользователем
- •Количественные характеристики программы
- •Текст программы
-
Проектирование конструкторов и деструкторов классов.
Конструкторы и деструкторы обеспечивают учет количества существующих в данный момент объектов класса. Конструкторы при создании присваивают каждому объекту уникальный ID.
Конструкторы и деструкторы «говорящие». При создании и уничтожении объектов выводятся не только названия классов, но и значения проблемных данных и ID объектов.
-
Разработка методики тестирования классов и тестовых наборов данных.
Для проверки работоспособности всех возможных ветвей разработанной программы достаточно одного теста:
-
Зарегистрировать клиента - Ошибка
-
Создать клиента №1 – Выполнено
-
Отправить сообщение от клиента 1 клиенту 2 - Ошибка
-
Зарегистрировать клиента 1 – Выполнено
-
Отправить сообщение от клиента 1 клиенту 2 - Ошибка
-
Создать клиента 2 – Выполнено
-
Зарегистрировать клиента 2 – Выполнено
-
Отправить сообщение от клиента 1 клиенту 2 – Выполнено
-
Отправить сообщение от клиента 1 всем – Выполнено
-
Выводы
Созданные классы точно соответствуют заданию и спецификации и корректно выполняют все поставленные задачи. Тестирующая программа полностью работоспособна и позволяет проверить все возможности разработанных классов.
Достоинство программы:
-
Решает поставленную задачу
-
Корректно работает на всех предложенных контрольных примерах
-
Имеет удобный интерфейс.
-
Говорящие конструкторы и деструкторы
Недостатков в программе не обнаружено.
-
Сценарий диалога с пользователем
Структура основного меню:
-
Создать нового клиента
-
Зарегистрировать клиента на сервере
-
Послать кообщение одниму из клиентов
-
Послать сообщеине всем клиентам
-
Список клиентов
-
Выйти из программы
Меню выводится циклически, т.е. появляется после выполнения каждой операции.
-
Количественные характеристики программы
Общая длина текста программы (в строках): 840. Из них:
Количество строк новых классов: 696
Количество строк тестирующей программы: 144
Общее количество классов, используемых в программе: 5
Количество новых (разработанных при выполнении работы) классов: 5
Общее количество заголовочных файлов: 5
Общее количество файлов-кодов: 6
Всего файлов: 11
Перечень имен новых классов:
Имя класса |
Длина текста (в строках) описания класса |
Общее количество функций класса, описанных вне класса |
CServer |
37 |
7 |
CClient |
36 |
9 |
CMsg |
31 |
5 |
CSrvList |
32 |
11 |
CSrvItem |
25 |
6 |
-
Текст программы
//Файл: Main.cpp
//Реализация почтовой системы средствами ООП
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
#include "Client.cpp"
void main()
{
int choice; //choice - переменная выбора пункта меню
// clrscr();
printf ("Реализация почтовой системы средствами ООП\n");
printf ("Автор: Сергеев М.В. гр.3352\n");
printf ("Дата: 21.05.06, Редакция: 1.0\n");
printf ("\n Создание нового сервера и списка клиентов\n");
// CView L; //создание нового вида
CServer* s = new CServer();
CSrvList* clients = new CSrvList();
getch();
do //цикл меню
{
clrscr();
printf ("\n");
printf ("Создать нового клиента.......................1\n");
printf ("Зарегистрировать клиента на сервере..........2\n");
printf ("Послать кообщение одниму из клиентов.........3\n");
printf ("Послать сообщеине всем клиентам..............4\n");
printf ("Список клиентов..............................5\n");
printf ("Выйти из программы...........................0\n");
printf ("Ваш выбор");
scanf("%d",&choice);
printf ("\n");
switch(choice) //выбор пункта меню
{
case 1: //
{
clients->insertItem(new CClient());
printf ("\n");
getch();
}
break;
case 2: //
{
int c;
cout<<"\n\nClient ID:";
cin>>c;
CClient* cl = clients->getClientByID(c);
if(cl == NULL)
{
cout<<"\nТакого клиента не существует";
}
else
{
int res = cl->regOnSrv(s);
cout<<"\nКлиент зарегистрирован. Результат:"<<res<<".";
}
printf ("\n");
getch();
}
break;
case 3: //
{
int from,to,c;
cout<<"\n\nClient ID:";
cin>>from;
CClient* cl = clients->getClientByID(from);
if(cl == NULL)
{
cout<<"\nТакого клиента не существует";
}
else
{
cout<<"\nID клиента получателя:";
cin>>to;
cout<<"\nMessage(число):";
cin>>c;
int res = cl->sendMsg(c,s,to);
cout << "\nСообщение отправлено. Результат"<<res;
}
printf ("\n");
getch();
}
break;
case 4: //
{
int from,c;
cout<<"\n\nClient ID:";
cin>>from;
CClient* cl = clients->getClientByID(from);
if(cl == NULL)
{
cout<<"\nТакого клиента не существует";
}
else
{
cout<<"\nMessage(число):";
cin>>c;
int res = cl->sendMsgAll(c,s);
cout << "\nСообщение отправлено всем клиентам. Результат"<<res<<".";
}
printf ("\n");
getch();
}
break;
case 5: //
{
printf ("\n\nКлиенты:");
clients->show();
printf ("\n");
getch();
}
break;
} //switch
} while(choice!=0);
clients->resetNextClient();
do{
CClient* c = clients->getCurClient();
delete c;
}while(clients->hasNextClient());
delete s;
getch();
}//main
//Файл: Server.h
//Класс "Сервер". Прототип.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#ifndef ServerH
#define ServerH
#include "Client.h"
//#include "SrvList.h"
#include "SrvList.cpp"
#include "Message.h"
class CClient;
class CServer
{
private:
CSrvList* clients; //registered clients
static int nextID;
const int id;
static int count;
public:
int regCl(CClient*); //register clients on server
int resend(CMsg*); //resend msg from registred user to registred user
int resendAll(CClient* from, int comm);
CServer(); //constructor
~CServer();//destructor
void show()const; //show info
int getID()const;
};
int CServer::nextID = 0;
int CServer::count = 0;
#endif
//Файл: Server.cpp
//Класс "Сервер". Реализация.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include "Server.h"
////////////////////////////////////////////////////////////////
/*
register client on server
0-registered
1-bad
*/
int CServer::regCl(CClient*c)
{
if(c==NULL)
{
cout<<"\nServer: Не верная ссылка на клиент";
return 1;
}
cout << "\nServer: Client(id "<<c->getID()<<")";
CClient* cl = clients->getClientByID(c->getID());
if(cl != NULL)
{
cout<<" Уже был зарегистрирован";
return 1;
}
clients->insertItem(c);
cout <<" Успешно зарегистрирован";
return 0;
};
////////////////////////////////////////////////////////////////
/*
send msg to reciver
0 - client read msg
1 - client not read msg
2 - client(reciver) not registred
3 - client(sender) not registred
*/
int CServer::resend(CMsg* m)
{
cout<<"\nServer: преслал ";
m->show();
CClient* c = clients->getClientByID(m->getFrom());
if(c == NULL)
{
cout <<"\nServer: Client(id "<<m->getFrom()<<")- не зарегистрирован(отправитель)";
return 3;
}
c = clients->getClientByID(m->getTo());
if(c == NULL)
{
cout <<"\nServer: Client(id "<<m->getTo()<<") - не зарегистрирован(получатель)";
return 2;
}
int res = c->readMsg(m);
if(res == 0 )
{
cout <<"\nServer: Client(id "<<m->getTo()<<") прочел сообщение";
m->show();
return 0;
}
cout <<"\nServer: Client(id "<<m->getTo()<<") не прочел сообщение";
m->show();
return 1;
}
////////////////////////////////////////////////////////////////
/*
send msg to all clients
-1 - not registred
0 -ok
>0 - how many not got message
*/
int CServer::resendAll(CClient* from, int comm)
{
cout<<"\n\nServer: Отсылается сообщение с командой "<<comm;
cout<<" всем клиентам от \n Client(id "<< from->getID()<<")";
CClient* c = clients->getClientByID(from->getID());
if(c == NULL)
{
cout <<"\nSServer: Client(id "<<from->getID()<<")- не зарегистрирован(отправитель)";
return -1;
}
clients->resetNextClient();
int res = 0, numCl = 0;
do{
CClient* c = clients->getCurClient();
CMsg* m = new CMsg(from->getID(),c->getID(),comm);
res += c->readMsg(m);
numCl++;
}while(clients->hasNextClient());
cout<<"\nServer: послал сообщение "<<numCl<<" клиентам. Из них не получили его "<<res;
return res;
}
////////////////////////////////////////////////////////////////
/*
Constructor
*/
CServer::CServer():id(nextID++)
{
count++;
clients = new CSrvList();
cout<<"\n>Server";
};
////////////////////////////////////////////////////////////////
/*
Destructor
*/
CServer::~CServer()
{
count--;
clients->clear();
cout<<"\n>~Server";
};
////////////////////////////////////////////////////////////////
/*
show info
*/
void CServer::show()const
{
cout<<"\nЗарегистрированные клиенты:";
clients->show();
}
////////////////////////////////////////////////////////////////
/*
get server id
*/
int CServer::getID()const
{
return id;
}
//Файл: Client.h
//Класс "Клиент". Прототип.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include "Message.h"
#include "Server.h"
#ifndef CClientH
#define CClientH
class CServer;
class CClient
{
private:
static int nextID;
const int id;
static int count;
public:
CClient(); //constructor
~CClient(); //destructor
int regOnSrv(CServer*s);//regiter on server
int readMsg(CMsg*m); //read message
int sendMsg(int com,CServer*s,int toID); //send msg to client #toID
int sendMsgAll(int com,CServer*s); //send msg to all client througth server
void show()const; //info
void showCInfo()const;
int getID()const; //getters
};
int CClient::nextID = 0;
int CClient::count = 0;
#endif
//Файл: Client.cpp
//Класс "Клиент". Реализация.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include "Client.h"
#include "Message.cpp"
#include "Server.cpp"
////////////////////////////////////////////////////////////////
/*
try to register on server
0-all right
1-bad
*/
int CClient::regOnSrv(CServer*s)
{
//cout<<"\nClient#"<<id<<" tries to reg on server #" << s->getID() << "...";
int res = s->regCl(this);
if(res == 0 )
{
cout<<"\nClient(id "<<id<<") зарегистрирован на Server(id "<<s->getID()<<")";
return 0;
}
cout<<"\nClient(id "<<id<<") не смог зарегистрироваться на Server(id "<<s->getID()
<<") Ошибка №"<<res;
return 1;
};
////////////////////////////////////////////////////////////////
/*
read message
0-read ok
1-bad
*/
int CClient::readMsg(CMsg*m)
{
cout <<"\nClient(id "<<id<<") получил ";
m->show();
if(m->getTo() == this->id){
//message ok, executing command
cout <<" Комманда: "<<m->getCommand();
return 0;
}
cout <<"Сообщение не мое";
return 1;
};
////////////////////////////////////////////////////////////////
/*
send msg to client #toID
*/
int CClient::sendMsg(int comm,CServer*s,int toID)
{
CMsg* m = new CMsg(this->getID(),toID,comm);
cout <<"\nClient(id "<<this->getID()<<") отправил ";
m->show();
int res = s->resend(m);
if(res==0)
cout <<"\nClient(id "<<this->getID()<<") Сообщение доставлено";
else
cout <<"\nClient(id "<<this->getID()<<") Сервер вернул:"<<res;
return res;
};
////////////////////////////////////////////////////////////////
/*
send msg to all client througth server
*/
int CClient::sendMsgAll(int comm,CServer*s)
{
cout <<"\nClient(id "<<this->getID()<<"): отсылает всем клиентам команду:"<<comm;
int res = s->resendAll(this, comm);
if(res==0)
cout<<"\nClient(id "<<this->getID()<<"): все сообщения доставлены";
else
cout<<"\nClient(id "<<this->getID()<<"): Сервер вернул:"<<res;
return res;
}
////////////////////////////////////////////////////////////////
/*
Constructor
*/
CClient::CClient():id(nextID++)
{
count++;
cout <<"\n>Client(id "<<id<<")";
};
////////////////////////////////////////////////////////////////
/*
Destructor
*/
CClient::~CClient()
{
count--;
cout <<"\n>~Client(id "<<id<<")";
};
////////////////////////////////////////////////////////////////
/*
show info about client
*/
void CClient::show()const
{
cout<<"Client(id "<<id<<")";
}
////////////////////////////////////////////////////////////////
/*
Show info: how many clients avaliable
*/
void CClient::showCInfo()const
{
cout << "\nКоличество клиентов:" << count <<".";
}
////////////////////////////////////////////////////////////////
/*
getter for id
*/
int CClient::getID()const
{
return id;
}
//Файл: Message.h
//Класс "Сообщение". Прототип.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#ifndef MessageH
#define MessageH
class CMsg
{
private:
int const from; //id клиента
int const to; //id сервера
int const command; //команда
static int nextID;
const int id;
static int count;
public:
int getFrom(); //Возвращает поле from
int getTo(); //Возвращает поле to
int getCommand(); //Возвращает тело
void show()const; //Возвращает информацию о сообщении
CMsg(int f,int t,int c); //Конструктор
};
int CMsg::nextID = 1;
#endif
//Файл: Message.cpp
//Класс "Сообщение". Реализация.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include "Message.h"
////////////////////////////////////////////////////////////////
int CMsg::getFrom() //Возвращает поле from
{
return from;
};
////////////////////////////////////////////////////////////////
int CMsg::getTo() //Возвращает поле to
{
return to;
};
////////////////////////////////////////////////////////////////
int CMsg::getCommand() //Возвращает тело
{
return command;
};
////////////////////////////////////////////////////////////////
CMsg::CMsg(int f,int t,int c):from(f),to(t),command(c),id(nextID++) //Конструктор
{
cout <<"\n>Message(id:"<<id<<" From:"<<from<<" To:"<<to<<" Body:"<<command<<")";
};
////////////////////////////////////////////////////////////////
void CMsg::show()const //Возвращает информацию о сообщении
{
cout <<" Message(id:"<<id<<" From:"<<from<<" To:"<<to<<" Body:"<<command<<")";
}
//Файл: SrvList.h
//Класс "Список клиентов на сервере". Прототип.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include "SrvElem.cpp"
#include "Client.h"
#ifndef __SrvList_H
#define __SrvList_H
class CSrvList
{
private:
CSrvItem* first; //First element of the list
CSrvItem* cur; //current for iterator
public:
CSrvList(); //construcor
~CSrvList(); //destructor
int isEmpty(void)const; //Check if the list is empty(1-empty, 0-not empty)
void insertItem(CClient*); //insert new item into the list
void clear(); //clear this list
void show()const;
CClient* getClientByID(int);
CSrvItem* getFirstPtr(); //get pointer to the first element
int hasNextClient(); //iterator
CClient* getCurClient();
void resetNextClient();
};
#endif
//Файл: SrvList.cpp
//Класс "Список клиентов на сервере". Реализация.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include "SrvList.h"
#ifndef __SrvList_CPP
#define __SrvList_CPP
////////////////////////////////////////////////////////////////
/*
Constructor
*/
CSrvList::CSrvList():first(NULL)
{
cout <<"\n>CSrvList";
};
////////////////////////////////////////////////////////////////
/*
Destructor
*/
CSrvList::~CSrvList()
{
this->clear();
cout <<"\n>~CSrvList";
};
////////////////////////////////////////////////////////////////
/*
Check if the list is empty (1-empty, 0-not empty)
*/
int CSrvList::isEmpty(void) const
{
return (first == NULL)? 1 : 0;
};
////////////////////////////////////////////////////////////////
/*
Insert item into the list with value of problem part val
*/
void CSrvList::insertItem(CClient*n)
{
//adding value to the list
CSrvItem* newItem = new CSrvItem(n,NULL);
if(first == NULL){
first = newItem;
}else{
CSrvItem* tmp = first;
while(tmp->getNext() != NULL){tmp = tmp->getNext();}
tmp->setNext(newItem);
}
};
////////////////////////////////////////////////////////////////
/*
Clearing all the list
*/
void CSrvList::clear()
{
if(first == NULL)
{
cout <<"\nCSrvList: Список клиентов очищен";
return;
};
if(first->getNext() == NULL)
{
delete first;
first=NULL;
cout <<"\nCSrvList: Список клиентов очищен";
return;
}
CSrvItem *tmp,
*t;
tmp=first;
t=first->getNext();
while(t->getNext()!=NULL)
{
delete tmp;
tmp=t;
t=t->getNext();
}
delete tmp;
delete t;
first=NULL;
cout <<"\nCSrvList: Список клиентов очищен";
};
////////////////////////////////////////////////////////////////
/*
Show List on the screen
*/
void CSrvList::show() const
{
cout<<"\n>>>\n";
if(first == NULL){cout<<" Зарегистрированных клиентов нет.\n<<<\n";return;}
int number = 0;
CSrvItem *tmpPtr;//temporary pointer to move throught the list
tmpPtr = first; //starting from the begining
//moving till the end
while(tmpPtr->getNext() != NULL)
{
//printing the inf of the item and move forward
tmpPtr->getPoint()->show();
cout<<"\n";
tmpPtr=tmpPtr->getNext();
number++;
}
tmpPtr->getPoint()->show();
number++;
cout <<"\nВсего:"<<number<<"\n<<<\n";
};
////////////////////////////////////////////////////////////////
/*
return pointer to the first element
*/
CSrvItem* CSrvList::getFirstPtr()
{
return first;
};
/*
get registered client with ID= id
*/
CClient* CSrvList::getClientByID(int id)
{
if(first == NULL){
return NULL;
}else{
CSrvItem* tmp = first;
if(tmp->getPoint()->getID() == id)return tmp->getPoint();
while(tmp->getNext() != NULL){
tmp = tmp->getNext();
if(tmp->getPoint()->getID() == id)return tmp->getPoint();
}
// tmp->setNext(newItem);
if(tmp->getPoint()->getID() == id)return tmp->getPoint();
}
return NULL;
}
////////////////////////////////////////////////////////////////
/*
walk by all - iterator
*/
int CSrvList::hasNextClient()
{
if(cur == NULL)return 0;
cur = cur->getNext();
if(cur == NULL)return 0;
return 1;
}
CClient* CSrvList::getCurClient()
{
if(cur == NULL) return NULL;
return cur->getPoint();
}
void CSrvList::resetNextClient()
{
cur = first;
}
#endif
//Файл: SrvElem.h
//Класс "Элемент списка клиентов на сервере". Прототип.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include "Client.h"
#ifndef __SrvElem_H
#define __SrvElem_H
class CSrvItem
{
private:
CClient* clientPtr; //problem part
CSrvItem *nextPtr; //next item
public:
CSrvItem(CClient*, CSrvItem *n); //constructor, filling all params
~CSrvItem(); //destructor
CSrvItem* getNext()const; //getters
CClient* getPoint()const;
void setNext(CSrvItem*); //setters
void setPoint(CClient*);
};
#endif
//Файл: SrvElem.cpp
//Класс "Элемент списка клиентов на сервере". Реализация.
//Автор: Сергеев М.В. гр.3352
//Дата: 21.05.06, Редакция: 1.0
#include<iostream.h>
#include<conio.h>
#include "SrvElem.h"
#ifndef __SrvElem_CPP
#define __SrvElem_CPP
////////////////////////////////////////////////////////////////
CSrvItem* CSrvItem::getNext()const
{
return nextPtr;
};
////////////////////////////////////////////////////////////////
CClient* CSrvItem::getPoint()const
{
return clientPtr;
};
////////////////////////////////////////////////////////////////
void CSrvItem::setNext(CSrvItem*n)
{
nextPtr=n;
};
////////////////////////////////////////////////////////////////
void CSrvItem::setPoint(CClient*p)
{
clientPtr=p;
};
////////////////////////////////////////////////////////////////
/*
Constuctor
*/
CSrvItem::CSrvItem(CClient*c, CSrvItem *n)
{
clientPtr = c;
nextPtr = n;
cout <<"\n>CSrvItem(id "<<c->getID()<<")";
};
////////////////////////////////////////////////////////////////
/*
Destructor
*/
CSrvItem::~CSrvItem()
{
cout <<"\n>~CSrvItem";
};
#endif