图书馆管理系统用户端心得
最近终于写了一个让自己满意的系统,我在这里分享一下,顺便总结一下自己的学习心得。
1.需求分析
听的好像是要做项目一样,但是无论写什么程序,些什么系统,都是要知道自己要干什么,要完成什么工作,实现那些功能,在这前列出一个表格,或是思维导图,给自己一个方向,先规划好再写,不然会拉下很多东西,在我写这个系统之前,我在图书馆的借书页面,看了将近两个小时,中途又看了好多次,这次代码不能说是一个完美可以当作工程性的使用,其中还有很多测试环节,还有部分功能没有实现,比如二次检索,三次检索功能,数据少得可怜,肯定还有一些未知的错误,所以我在这里真是分享我写代码,及调试代码的方法跟过程。
2.写代码+调试代码
写代码的时候一定要写一个功能调试一个功能,所谓的一个功能不是一个类,而是一个类的一个函数,如果一个函数会影响到其他函数的运行,不调好之前的函数,现在的函数也没法运行,当代码随着项目的增大,代码长度几何增长是,再找错误就很难的了,所以顺着调试下去,以便你写完的代码是可以运行的,是正确的,而具体能否实现功能在另说。
数据类与操作类的分离,面向对象要的是封装性,操作抽象+数据抽象,继承,写代码写完能够复用最好,乱糟糟的写完不能复用的类扔在那里,以后再也不会用到,浪费时间,完全可以写一些代码条理清晰,更重要的是,下次相似的代码不用再继续写,这应该是应该具备的素养。
以下是我调试代码的过程,最后代码还是有一点错误,这里是我的明明还是不好的原因,补充一下我认为明明一定要有意义,可以将学生的每科学分定义为a b c d. …也可以定义为数学 英语 物理 c++…这样可以增加代码的可读性。
引以为戒:
下文中这两个MAP混用导致了一些问题,以至于我交代码的时候是错误的还有没有发现
map<string,int>idtorea; //读者id对应读者数据下标
map<string ,int> idtoob; //图书id对应图书数据下标
时间类
时间类第一次调试运行,测试有参无参,重载<< ,>>和+
写到后边发现,自己重载的+错了,而且还需要计算两个时间类相差的时间,回头从新写的重载+,跟-
图书类
这里调试很多遍,开始留了一个应还时间Time类,后来发现,没有用。
后来想到,可能查询归还时间,所以写了get函数,但是函数不能反回局部类对象,只好写成static。
因为后边的时候需要输出,但是有些数据只有管理员能够看到,所以写完后边的回来写的print函数。
读者类
这里学生能做的事情不多,修改密码,查询个人信息,别的都做不了。
在后边实现借书就要在数据类中实现更改,所以在这里加了一条进行测试所添加的操作。
操作数据类
每一条新数据都必须,拥有参初始化,除了文件读取除外。
操作类也面临着不能直接输出的尴尬境界,所以回来,再写一个print。
终于看到自己的程序成功运行,也试了几组错误情况。基本无问题。
#include<bits/stdc++.h.>
using namespace std;
class Time
{
int year,month,day;
public:
Time(){loadtime();}
Time(int y,int m,int d):year(y),month(m),day(d){}; //用与图书出版日期等已知数据的对象的初始化;
//不能创建图书对象,有参初始化就没意义。
// Time(Time & a){year=a.year,month=a.month,day=a.day;} //用一个时间类初始化一个时间类,为后续操作准备;
//这句不注释就没法运行,不得解
void loadtime(); //定义时间获取函数,学生借书的时间不可更改,直接从系统读入;
friend istream & operator>>(istream &in,Time & a); //不设置set函数,时间直接一次性全部修改即可;
friend stringstream & operator>>(stringstream &in,Time & a);
friend ostream & operator<<(ostream &out,Time & a);
bool operator <(const Time &d)const{ //重载小于号,用于数据时间排序,不需要修改数据const;
return year!=d.year?year<d.year:month!=d.month?month<d.month:day<d.day;
}
int judge() const; //判断是否为闰年,用于续借日期的变化;
int judge(int year) const ;//写一个有参的判断函数;
Time operator +(int a) ; //重载加号,用于续借日期的变化;
friend int operator -(Time a,Time b); //计算两段时间间隔;
};
Time Time::operator +(int a)
{
int m[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
day+=a;
int flag=1;
while(day>m[month]){
if(month==2){
if(day>m[month]+judge()){
day-=m[month]+judge();
month++;
}
}
else {
day=day-m[month];
month++;
}//因为一对大括号跑了好几遍,敲ACM也一样,不要偷懒
if(month>12){
month-=12;
year++;
}
}
}
int operator -(Time a,Time b)
{
int monthdays[2][12] = { { 31,28,31,30,31,30,31,31,30,31,30,31 },{ 31,29,31,30,31,30,31,31,30,31,30,31 } };
int yeardays[2] = { 365,366 };
int sumdays=0;
if (a.year == b.year&& a.month == b.month){
sumdays = b.day - a.day;
}
else
if (a.year == b.year){
sumdays += monthdays[a.judge(a.year)][a.month-1] - a.day;
for (int i = a.month; i < b.month-1; i++)
sumdays += monthdays[a.judge(a.year)][i];
sumdays += b.day;
}
else{
sumdays += monthdays[a.judge(a.year)][a.month-1] - a.day;
for (int i = a.month; i < 12; i++)
sumdays += monthdays[a.judge(a.year)][i];
for (int i = a.year + 1; i < b.year; i++)
sumdays += yeardays[a.judge(i)];
for (int i = 0; i < b.month - 1; i++)
sumdays += monthdays[a.judge(b.year)][i];
sumdays += b.day;
}
return sumdays;
}
int Time::judge() const{
if(year % 4 == 0 && year %100 != 0 ||year % 400 == 0) return 1;
else return 0;
}
int Time::judge(int year) const{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)return 1;
else return 0;
}
void Time::loadtime(){
time_t rawtime;
struct tm *ptminfo;
time(&rawtime);
ptminfo = localtime(&rawtime);
year=ptminfo->tm_year + 1900;
month=ptminfo->tm_mon + 1;
day=ptminfo->tm_mday;
}
istream & operator>>(istream &in,Time & a){
in>>a.year>>a.month>>a.day;
return in;
}
ostream & operator<<(ostream &out,Time & a)
{
out<<a.year<<" "<<a.month<<" "<<a.day<<" ";
return out;
}
stringstream & operator>>(stringstream &in,Time & a){
in>>a.year>>a.month>>a.day;
return in;
}
/*
int main()
{
Time demo1;//无参初始化对象
cout<<demo1<<endl;
Time demo2(demo1);//有参初始化对象,便于不同时间定义对象,时间不同;
cout<<demo2<<endl;
demo2+60;//为续借,即还书时间做准备;
cout<<demo2;
Time demo3(2000,03,19);
cout<<demo3<<endl;
}
*/
/*
int main()
{
Time demo1,demo2;
cin>>demo1>>demo2;
int d=demo1-demo2;
demo1+d;
cout<<demo1<<endl;
cout<<d<<endl;
}*/
class Book
{
string name;
string press; //出版社
string pubtime; //出版时间通常在图书馆只有年份
string author; //作者
string suoshu; //索书号
string id; //每本书都有唯一的条形码,两本完全一样的书,在这里应该看作两本书
string locate;
string jsr; //指向借书人数据在的位置的下标(-1),代表可借
int fk; //每本书都有自己的罚款,不会影响其他书籍,定义在这里比定义在读者类要合适
bool xj; //比起写入记录中查询,写在图书中,无论是还书,还是续借,都更加便捷
Time jy;
// Time rebac;
public:
Book():name(""),press(""),author(""),id(""),suoshu(""),locate(""),jsr("-1"),fk(0){}
//学生端不能创建书籍对象,只写一个无参初始化,用于读取文件数据;
string getname ()const{return name;}
string getpress ()const{return press;}
string getauthor ( )const{return author;}
string getpubtime ( )const{return pubtime;}
string getid ( )const{return id;}
string getsuoshu ( )const{return suoshu;} //通过上述get函数为下面的查询做准备;
int getfk(){jsfk();return fk;}
void xxj(){
/*if(fk<=0)xj=!xj;
else cout<<"请先缴清罚款"<<endl;*/ //改为在读者类判断,不只是一本书的罚款,会影响借书;
xj=!xj;
}
bool getxj(){ return xj;}
void js(string idcard){jsr=idcard;} //学号跟图书的条形码是唯一的,由此来对应;
Time& getreback();
void jsfk();
void print();
friend istream & operator>>(istream &in,Book & a);
friend ostream & operator<<(ostream &out,Book & a);
};
void Book::jsfk()
{
int brr;
if(xj) brr=120;
else brr=60;
Time tem;
fk=tem-jy-brr;
if(fk<0) fk=0;
}
void Book::print()
{
cout<<name<<" "<<press<<" "<<author<<" "<<id<<" "<<suoshu<<" "<<locate<<" ";
if(jsr!="-1") cout<<"已借出 归还时间:"<<getreback()<<endl;
else cout<<endl;
}
Time& Book::getreback(){
static Time tem(jy);
tem+60*(1+getxj());
return tem;
}
istream & operator>>(istream &in,Book & a){
in>>a.name>>a.press>>a.pubtime>>a.author>>a.suoshu>>a.id>>a.jsr>>a.locate>>a.jy>>a.xj;
return in;
}
ostream & operator<<(ostream &out,Book & a){
out<<a.name<<" "<<a.press<<" "<<a.pubtime<<" "<<a.author<<" "<<a.suoshu<<" "<<a.id<<" "<<a.jsr<<" "<<a.locate<<" "<<a.jy<<" "<<a.xj;
return out;
}
//记 北京机械工业出版社 2016 胡凡 TP301.6/H569 01664298 123456 -1 采编部在编 2018 5 16 1
/*
int main()
{
Book demo;
cin>>demo;
cout<<demo;
cout<<demo.getname()<<endl;
cout<<demo.getpress()<<endl;
cout<<demo.getauthor()<<endl;
cout<<demo.getsuoshu()<<endl;
cout<<demo.getpubtime()<<endl;
cout<<demo.getfk()<<endl;
int jsr;
cin>>jsr;
demo.js(jsr);
cout<<demo.getxj()<<endl;
demo.xxj();
cout<<demo.getxj()<<endl;
cout<<demo<<endl;
} //算法笔记 北京机械工业出版社 2016 胡凡 TP301.6/H569 01664298 123 采编部在编 2018 5 16 1
*/
/*
int main()
{
Book demo;
cin>>demo;
cout<<demo.getreback();
}*/
/*
int main()
{
Book demo1;//无参初始化对象
cin>>demo1;
demo1.print();
}
*/
class Student
{
string name;
string id;
string key;
string mail;
vector<string> jy;/*按时间先后借的书,则为有序,int是图书数据的ID;
通过下标联通了图书与读者。*/
int yj;//已借图书
public:
Student() :name(""),id(""),key(""),mail(""){jy.clear();}
//void printxx() 想写打印信息的功能,但是目前这个类看不到图书数据,无法关联。转而写get函数;
vector<string> getjy() const{return jy;} //先返回一个vector对象,目前看不到图书数据,所以返回后,在操作类中使用
string getname(){return name;}
string getid(){return id;}
string getkey(){return key;}
string getmail(){return mail;}
int getyj()const {return yj;}
void setkey(string tem) ; //修改密码
void jieyue(string obid); //借阅图书,图书馆的借阅最后都是按照书的唯一的条码来借阅
void reback(string obid); //归还同上。
/*现在看不到图书数据,只能写出部分借阅,归还操作,在操作类中应判断是否具有罚款,
此函数仅用于修改学生,作为子函数使用*/
friend istream & operator>>(istream &in,Student & a);
friend ostream & operator<<(ostream &out,Student & a);
} ;
istream & operator>>(istream &in,Student & a)
{
in>>a.name>>a.id>>a.key>>a.mail>>a.yj;
string tem;
for(int i=0;i<a.yj;i++) {
in>>tem;
a.jy.push_back(tem);
}
return in;
}
ostream & operator<<(ostream &out,Student & a)
{
out<<a.name<<" "<<a.id<<" "<<a.key<<" "<<a.mail<<" "<<a.yj<<" ";
for(int i=0;i<a.yj;i++) cout<<a.jy[i]<<" ";
return out;
}
void Student::jieyue(string obid)
{
if(yj>=10) cout<<"借阅数量已达上限"<<endl;
else jy.push_back(obid);
yj=jy.size();
}
void Student::reback(string obid) //归还操作很宽泛,甚至都不需要登陆账号,但是根据图书找到人,最后还是要根据id在这人身上去掉
{
//不需要容错,如果系统不崩溃,从书籍查借人一定是唯一的
auto po=find(jy.begin(),jy.end(),obid);
if(po==jy.end()) cout<<"还书失败,请联系管理员"<<endl;
else jy.erase(po);
yj=jy.size();
}
void Student::setkey(string tem)
{
while(tem!=key)
{
cout<<"密码错误,请重试"<<endl;
cin>>tem;
}
cin>>tem;
key=tem;
}
/*
int main()
{
Student demo;
cin>>demo;
cout<<demo.getname()<<endl;
cout<<demo.getid()<<endl;
cout<<demo.getkey()<<endl;
cout<<demo.getmail()<<endl;
cout<<demo.getyj()<<endl;
cout<<demo;
}*/
//张俊浩 2018212513 123456 529934209@qq.com 1 203
/*
int main()
{
string tem;
Student demo;
cin>>demo>>tem;
demo.jieyue(tem);
cout<<demo<<endl;
cin>>tem;
demo.reback(tem);
cout<<demo;
}
*/
class Operate //记录只能生成不能修改
{
Time time;
string oper; //操作
string peo; //操作人id
string boo; //图书对象ID
int fk; //当操作为还书时有真实罚款,其余为-1
public:
Operate( ):oper(""),peo(""),boo(""),fk(-1){} //仅用于文件读写
Operate(string o,string p,string b,int c):oper(o),peo(p),boo(b),fk(c){time.loadtime();} //操作无论管理员,学生都无法改变时间;
string getname(){return peo;}
string getbook(){return boo;}
string getoper(){return oper;}
int getfk(){return fk;} // 用于后续查询操作
void print() ;
friend istream & operator>>(istream &in,Operate & a);
friend ostream & operator<<(ostream &out,Operate & a);
} ;
void Operate::print()
{
cout<<time<<" "<<peo<<" "<<oper<<" "<<boo<<" ";
if(fk!=-1) cout<<"缴纳罚款:"<<fk<<endl;
}
istream & operator>>(istream &in,Operate & a)
{
in>>a.time>>a.peo>>a.oper>>a.boo>>a.fk;
return in;
}
ostream & operator<<(ostream &out,Operate & a)
{
out<<a.time<<" "<<a.peo<<" "<<a.oper<<" "<<a.boo<<" "<<a.fk<<" ";
return out;
}
/*
int main()
{
Operate demo;
cin>>demo;
cout<<demo.getname()<<" "<<demo.getoper()<<" "<<demo.getbook()<<" "<<demo.getfk()<<endl;
cout<<demo<<endl;
string name,op,ob;
int fk;
cin>>name>>op>>ob>>fk;
Operate demo2(name,op,ob,fk);
cout<<demo2<<endl;
}
*/
/*
int main()
{
Operate demo;
cin>>demo;
demo.print();
}*/
class Library
{
string account;
string password; //每次登入图书馆进行操作都要有账号密码
vector<Book> book;
vector<Student> reader;
vector<Operate> record; //三个基础数据;
//图书查询操作所需数据
multimap<string,int> pubtimque; //出版时间
multimap<string,int> suoshuque; // 索书号
multimap<string,int> pressque; //出版社
//书名与作者都需要模糊查询
//数据查询
map<string,int>idtorea; //读者id对应读者数据下标
map<string ,int> idtoob; //图书id对应图书数据下标
multimap<string,int> ridtorec; //读者Id对应操作数据下标
multimap<string,int> bidtorec; //图书 id对应操作数据下标
public:
Library(string ac,string pass): account(ac),password(pass){load();login();cout<<book.size();}
void login();
//书籍查询操作
void querysm(string name) ;//书名查询
void queryss(string suoshu) ; //索书号查询
void queryath(string ath); //作者查询
void querypres(string pre); //出版社查询
void querytim(string pub);//出版时间查询
//个人信息操作
void quepers(); //查询读者身份信息
void quebrro();//查询借阅信息
void queop(); //查询读者操作记录(仅个人)
//基础操作
int cxkj(); //查询课可借书的数量
void jieshu(string id) ;
void huanshu(string id);
void xujie(string id); //图书馆虽然不用输入书的条码,但是现在也是通过书的磁获取
//也应该看是输入,比如某些地方仍用扫码,甚至手输
void load();
void save();
~Library(){save();}
};
//有些map是给管理端用的,这里只写不读;
void Library::login()
{
while(1){
auto po=idtorea.find(account);
if(po!=idtorea.end()&&reader[po->second].getkey()==password) break;
cout<<"账号密码不匹配\n请重新输入\n"; //可以在分个账号不存在,但看很多网站,
//都不会报不存在,为了提高一点安全性;
cin>>account>>password;
}
cout<<"登陆成功\n";
}
void Library:: querysm(string name)
{
for(auto po=book.begin();po!=book.end();po++)
{
auto m=po->getname().find(name);
if(m!=-1) po->print();
}
}
void Library:: queryss(string suoshu)
{
auto beg=suoshuque.lower_bound(suoshu);
auto en=suoshuque.upper_bound(suoshu);
for(auto po=beg;po!=en;po++)book[po->second].print();
}
void Library:: queryath(string ath){
for(auto po=book.begin();po!=book.end();po++)
{
auto m=po->getauthor().find(ath);
if(m!=-1) po->print();
}
}
void Library:: querypres(string pre)
{
auto beg=pressque.lower_bound(pre);
auto en=pressque.upper_bound(pre);
for(auto po=beg;po!=en;po++) book[po->second].print();
}
void Library:: querytim(string pub)
{
auto beg=pubtimque.lower_bound(pub);
auto en=pubtimque.upper_bound(pub);
for(auto po=beg;po!=en;po++)book[po->second].print();
}
void Library:: quepers(){
cout<<reader[idtoob[account]].getname()<<" ";
cout<<reader[idtoob[account]].getid()<<" ";
cout<<reader[idtoob[account]].getmail()<<" ";
cout<<reader[idtoob[account]].getyj()<<" ";
cout<<cxkj()<<endl;
}
void Library:: quebrro()
{
for(auto po=reader[idtoob[account]].getjy().begin();
po!=reader[idtoob[account]].getjy().end();po++)
book[idtoob[ *po]].print();
}
void Library:: queop()
{
auto beg=ridtorec.lower_bound(account);
auto en=ridtorec.upper_bound(account);
for(auto po=beg;po!=en;po++)record[po->second].print();
}
int Library:: cxkj()
{
int ans=0;
for(auto po=reader[idtoob[account]].getjy().begin();
po!=reader[idtoob[account]].getjy().end();po++)
ans+=book[idtoob[ *po]].getfk();
if(ans>0) return -1;
else return 10-reader[idtoob[account]].getjy().size();
}
void Library:: jieshu(string id)
{
if(cxkj()==-1){ cout<<"归还逾期,请先归还\n"; return ;}
else if(cxkj()==0) { cout<<"达到借书上限\n"; return ;}
reader[idtorea[account]].jieyue(id);
book[idtoob[id]].js(account);
Operate tem("借书",account,id,-1);
record.push_back(tem);
ridtorec.insert(make_pair(account,record.size()-1));
bidtorec.insert(make_pair(id,record.size()-1));
}
void Library:: huanshu(string id)
{
reader[idtorea[account]].reback(id);//异常在 reback抛出
book[idtoob[id]].js("-1");
int money=book[idtoob[id]].getfk();
Operate www("还书",account,id,money);
record.push_back(www);
ridtorec.insert(make_pair(account,record.size()-1));
bidtorec.insert(make_pair(id,record.size()-1));
}
void Library:: xujie(string id)
{
if(cxkj()==-1){ cout<<"归还逾期,请先归还\n"; return ;}
else if(cxkj()==0) { cout<<"达到借书上限\n"; return ;}
book[idtoob[id]].xxj();
Operate tem("续借",account,id,-1);
record.push_back(tem);
ridtorec.insert(make_pair(account,record.size()-1));
bidtorec.insert(make_pair(id,record.size()-1));
}
void Library::save()
{
ofstream out1("d:\\book.txt",ios::out);
for(auto po=book.begin(); po!=book.end(); po++)
out1<<*po<<endl;
out1.close();
ofstream out2("d:\\reader.txt",ios::out);
for(auto po=reader.begin(); po!=reader.end(); po++)
out2<<*po<<endl;
out2.close();
ofstream out3("d:\\record.txt",ios::out);
for(auto po=record.begin(); po!=record.end(); po++)
out3<<*po<<endl;
out3.close();
}
void Library:: load()
{
ifstream in1("d:\\book.txt",ios::in);
if(in1)
{
Book tem1;
book.clear();
while(in1>>tem1)
{
book.push_back(tem1);
idtorea.insert(make_pair(tem1.getid(),book.size()-1));
pubtimque.insert(make_pair(tem1.getpubtime(),book.size()-1));
suoshuque.insert(make_pair(tem1.getsuoshu(),book.size()-1));
pressque.insert(make_pair(tem1.getpress(),book.size()-1));
}
in1.close();
}
ifstream in2("d:\\reader.txt",ios::in);
if(in2)
{
reader.clear();
Student tem2;
while(in2>>tem2)
{
reader.push_back(tem2);
idtorea.insert(make_pair(tem2.getid(),reader.size()-1));
}
in2.close();
}
ifstream in3("d:\\record.txt",ios::in);
if(in3)
{
record.clear();
Operate tem3;
while( in3>>tem3)
{
record.push_back(tem3);
ridtorec.insert(make_pair(tem3.getname(),record.size()-1));
bidtorec.insert(make_pair(tem3.getbook(),record.size()-1));
}
in3.close();
}
}
int main()
{
string account,key,name,suoshu,ath,pre,pub,id;
cin>>account>>key;
Library demo(account,key);
cin>>name;
demo. querysm( name) ;//测试书名查询
cin>>suoshu;
demo. queryss( suoshu) ; //测试索书号查询
cin>>ath;
demo. queryath( ath); //测试作者查询
cin>>pre;
demo. querypres( pre); //测试出版社查询
cin>>pub;
demo. querytim( pub);//测试出版时间查询
//测试个人信息操作
demo. quepers(); //测试查询读者身份信息
demo. quebrro();//测试查询借阅信息
demo. queop(); //测试查询读者操作记录(仅个人)
//测试基础操作
demo. cxkj(); //测试查询课可借书的数量
cin>>id;
demo. jieshu( id) ;
cin>>id;
demo. huanshu( id);
cin>>id;
demo. xujie( id);
return 0;
}