第十三章 图书馆管理系统设计
在实际系统中,怎么样用面向对象的思想来编写系统是
很重要的,下面以建立一个 〈 图书馆管理系统 〉 为例子,看
看我们怎么样用学过的知识来组织数据、来设计程序。
1,数据的组织
对象的 识别:
在一个信息管理系统内 识别对象 是数据组织中很重要的一
步,识别时候我们从问题中根据业务的流程,操作对象来进
行,识别出一个对象后,我们就可以把具有公共特性的对象
归纳为 类 。然后在类的基础,分析他们之间的关系,形成若
干个类的层次结构。
在图书馆流通系统内,我们知道,有书、读者、借书证、
管理人员、借书还书行为等对象和事件,他们分别各是一个
群体。例如每个图书馆都有几万甚至几十万册图书,每册图
书都是一个对象,它们形成图书类( Book),在图书流通系
统内,还有以下类:
读者 (Reader)类,图书借阅信息类( Loan),管理人员类
( Manager),是借书还书行为的操作人。对于借书证对象。
我们只记录它的编号,作为读者类的一个数据成员。同一个信
息系统,从不同的角度分析,或根据要求的不同,有不同的侧
重面,这样建立的对象模型不同,可能得出的分类方法也不同。
类数据 属性的识别:
每个对象的情况称为 对象的属性,同类型的对象具有共同
的属性,只是每个对象的属性值不一定相同。属性是对一个对
象状态的描述,如“在馆图书类”,从流通管理的角度来看,
图书类:书名 Title、作者名 Author、分类号 IndexCode、册
数 Number、条码号 BarCode等属性。
读者类:姓名 Name、年龄 Age、借书证编号 Bozid等。
一个读者允许借阅若干册书,在此用一个 Book类的
链表 Bkp保存相应信息。另外对读者所借书册数要
统计,定义一个计数的成员 Count;
借阅信息类:所借书 book、借书人 reader、操作员 manager
13.1 数据分析和组织
13.1 数据分析和组织
管理人员类:姓名 Name、年龄 Age、工号 Code等;
同一个类(对象),从不同的角度分析,或根据要求的不同,
描述它的属性也可能不一致。
类成员函数 的设计:
就是对象的操作,在图书馆流通管理系统内,图书类 应包
含为各属性赋值 (Set…) 的操作、读取条码 (GetCode)和显示图
书基本信息 (Show)的操作,另外还定义了缺省构造函数和拷贝
构造函数。 读者类,需定义为各属性赋值 (Set…) 的操作、读取
借书证号的操作,借书和还书需要向所借书数组中添加或减少
书,定义 AddBook和 DelBook两个操作,还有显示所借书的操
作 ShowBooks。
类的层次结构设计:
对于图书来说,我们知道,在图书馆中,一般有两类:书
籍和杂志,书籍具有图书的一般属性( 书名、条码等共性) 之
外,还有 作者、分类号等特性,
13.1 数据分析和组织
而杂志也是图书的一种,对于现刊,是以期为借阅单位,对于
过刊以卷( Volume)为借阅单位,为简化问题,我们只处理
过刊借阅,即以卷为借阅单位,每卷分配一个条码。与书籍的
不同之处在于,杂志没有单一的作者,只以刊名和卷号借阅。
书籍和杂志图书都有书(杂志)名、条码等共性,都有设置
条码、读取条码及显示等接口,提取二者的共性和公共接口,
定义一个 图书类 Book,作为基类 。然后 派生出 Item书籍和
Magazine杂志两个类。 Item有作者、分类号等特性,
Magazine有卷号、语言等特性。
Book
Item Magazine
13.2 类的定义
class Book { // 图书基类
protected:
char Title[40]; // 书名
long Code; // 条码
int number; // 书的册数
public:
Book();
Book(char *title,long code,int nb);
void SetCode(long code) { Code = code; }
void SetTitle(char* tl) { strcpy(Title,tl); }
char *GetTitle() { return Title; }
long GetCode() { return Code; }
int GetNumber( return Number; }
void ChangeNumber(int d)
{ if(Number == 0 && d < 0) return; Number += d; }
virtual void Show(); // 显示函数定义为虚函数
friend ostream &operator << (ostream &os,Book &bk){
Show(); // 重载借阅信息类插入符
return os; }
};
13.2 类的定义
class Item,public Book { // 书籍类
char Author[20]; // 作者
char IndexCode[10]; // 分类号
public:
Item(); // 缺省构造函数
Item(char *author,char *title,char *index,
int code):Book(title,code) {
strcpy(Author,author); IndexCode = index; // 构造函数
Item(Item & it) { // 拷贝构造函数
strcpy(Title,it.Title); Code = it.Code;
strcpy(Author,it.Author); IndexCode = it.IndexCode;
}
void SetAuthor(char *);
void SetIndexCode(char *);
void Show() { // 重定义显示函数
cout <<,书名:” << Title <<,,作者:” << Author <<
endl;
}
};
13.2 类的定义
class Magazine,public Book { // 杂志类
int Volume;
enum LANG {CHINESE=1,ENGLISH} Lang; // 语言种类
public:
Magazine ():Book() {
Volume = 0; Lang = CHINESE; Type = 1; }
Magazine (char * title,int vol,LANG lang,
int code):Book(titlem code)
{ Volume = vol; Lang = lang; } // 构造函数
Magazine (Magazine & ma); // 拷贝构造函数
void SetVolume (int vol) { Volume = vol; }
void SetLang (int lang ) { Lang = (LANG)lang; }
void Show ( ) // 重定义显示函数
{cout <<,杂志名:” << Title<<,,卷号:” <<Volume
<<endl;}
};
读者类要存储所借书。现在图书类一个派生类体系,它们的公共基
类 Book提供了统一接口。 可定义 一个 单链表来同时存储读者所借书籍
Item和杂志 Magazine 。 Book类有一个指向 Book类的指针 Next,
用来构成链表。
13.2 类的定义
class Reader { // 读者类
protected:
char Name[40]; // 书名
long Bozid; // 借书证编号
int Age; // 年龄
int Count; // 借书数目
BkNode * Bkp; // 借的书单向链表头指针
public:
Reader();
Reader(char *n,long bd,int age) {
strcpy(Name,n); Bozid = bd; Age = age;
books = NULL; count = 0;
}
void SetCount(int c) { Count = c; }
long GetBkid() { return Bozid; }
long GetCount() { return Count; }
13.2 类的定义
void AddBook(Book * bk) { // 添加书籍
BkNode *p = new BKNode;
p->Data = bk;
if(Bkp) {
p->Next = Bkp; // 插入表头,
items = p;
Count ++;
}
else {
Bkp = p;
p->Next = NULL;
}
}
void DelBook(long code) { // 删除书籍
BkNode *p1 = Bkp,*p2;
while(p1) {
if(p1->Data->GetCode == code) { // 找到条码的书
p2->next = p1->next;
delete p1;
}
else {
p2 = p1;
p1 = p1->next;
}
}
}
void Show(); // 显示函数定义为虚函数
};
13.2 类的定义
void ShowBooks() { // 显示所借的所有书
BkNode p = Bkp;
while(p) {
p->Data->Show() ; // 显示书籍或杂志,动态联编
p = p->next;
}
}
};
而对于整个图书馆系统,我们可以用面向对象的思想进行
整体封装,定义一个 Library 类,类中有书籍对象数组、杂志
类对象数组、读者类数组、借阅信息类数组和管理者对象数组,
还有每个数组的实际数目等 数据成员,然后再定义 Borrow,
BackBook,Require,CreateItem,CreateMagazine,
CreateManager,CreateReader,ShowMainMenu,
Run 等 成员函数来 处理图书馆流通业务。
13.2 类的定义
13.2 类的定义
Library类的成员函数中多了一个 Run函数,这是图书馆
业务开始执行的入口,如创建书目、读者信息、管理员信息等,
主菜单的显示、借书、还书、查询等也全放在 Run中。
图书馆类的定义如下:
class Library{ // 封装图书馆流通
Item item[100]; // 记录书籍的数组
Magazine maga[100]; // 记录杂志的数组
Reader reader[100]; // 记录读者的数组
Load loan[100]; // 记录借阅信息的数组
Manager manager[10]; // 记录管理员的数组
int itemNum; // 记录在馆书籍数目
int magaNum; // 记录在馆杂志数目
int readerNum; // 记录读者数目
int loanNum; // 记录借阅信息数目
int managerNum; // 记录管理员数目
public:
Library(); // 构造函数
void Run(); // 运行图书馆业务函数
void CreateItem(); // 创建书籍
void CreateMagazine(); // 创建杂志
void CreateReader(); // 创建读者
void CreateManager(); // 创建管理员
int ShowMainMenu(); // 显示主菜单
void Borrow(); // 借书操作
void BackBook(); // 还书操作
void Require(); // 查询操作
};
上面列出主要的几个类的具体实现,对于其他借阅信息类
和管理人员类就不描述了,同学们可自行设计。
下面就这些类之间的数据通讯和借书、还书的业务具体操
作及主控函数的实现作简单的介绍。
13.2 类的定义
13.3 对象之间的数据通讯
定义了类和对象,
它们之间就可以互
相 通讯,完成特定
的功能了。左图表
示了对象之间的相
互通讯关系。
图书流通管理系统的对象
13.3 对象之间的数据通讯
定义了信息系统的数据结构和它们的操作,即可用程序实现。
首先定义主函数:
main函数所要做的就是定义 一个 Library的对象,然后 调
用该对象的 Run函数,
void main(){
Library lib; // 定义图书馆类对象
lib.Run(); // 开始执行图书馆功能
return;
}
上面的定义更符合面向对象的设计思想。
在 lib.Run函数中,执行时显示主菜单,首先选择创建书目、
读者信息、管理员信息等;然后若选择借书,提示输入借书证号
和书的条码,根据借书证号找到读者,根据书的条码找到要借的
书,将所借书添加到读者的所借书的链表中,并从可借书中的数
量减 1。还书的过程跟借书差不多;查询则可从不同角度来查询,
如读者的借书情况,某书的剩余数,借书排行榜等
13.4 主要函数的实现框架
void Library::Borrow(){ // 借书操作
long bkd,code;
Loan ln; Book *it;
cout << "借书,请输入借书证号码,"; cin >> bkd;
for(int i = 0; i<readerNum; i++) { // 查找读者
if(bkd == reader[i].GetBkid()) break;
}
if(i == readerNum) {
cout<<“没有此借书证号码,请重新输入! \n"; return;
}
cout <<,借书,请输入书的条码,"; cin >> code;
for(int j=0;j<itemNum+magaNum; j++) {//书籍和杂志查找
if(j < itemNum) it = &item[j];
else it = maga[j - itemNum];
if(it->GetCode() == code) { // 若找到书
if(it->GetNumber() > 0) { // 书库中还有书
it->ChangeNumber(-1);
reader[i].AddBook(& it); //加到读者所借书数组
}
13.4 主要函数的实现框架
else {
cout <<,该书被借光了 !” << endl;
return;
}
}
}
cout << "请输入管理员工号,";
cin >> code;
for(k=0; k < managerNum; k++){ //查找管理员
if(manager[k].GetId == code) break;
}
ln.manager = manager[k]; //添加借阅信息
ln.reader = reader[i];
ln.item = it;
loan[loanNum++] = ln;
return ;
}