学习重点:数据的输入输出,项目层次划分
学习难点:完善该ATM项目,模拟生产环境
/*
*Account类是与业务和存储无关的类,应该保持最大程度的稳定性,
*尽量减少业务方法,所有的方法应该只与类本身有关系
*/
/*
*覆盖无参构造函数,初始化各个属性
*/
account::account(){
id = -1 ;
memset( name , 0 , sizeof( name ) );
memset( pwd , 0 , sizeof(pwd) );
balance = 0 ;
}
/*
*重载有参构造函数,根据传入的参数初始化成员属性
*/
account::account( char* name , char* pwd ,double b){
id = generateId();
strcpy( this->name , name ) ;
strcpy( this->pwd , pwd ) ;
balance = b ;
}
/*
*存款操作,用于增加存款
*/
void account::save( double s ){
balance += s ;
}
/*
*取款操作,形参是密码和金额
*/
void account::withdraw( char* p, double s){
/*
*如果密码不正确,抛出异常,跳出程序
*/
if( strcmp( p , pwd ) != 0 ){
throw "invalid password" ;
}
/*
*如果余额不足,抛出异常,跳出程序;至少留有10元的年费
*/
if( balance < s + 10 ){
throw "no enough money" ;
}
/*
*如果密码不正确,抛出异常
*/alance -= s ;
}
/*
*查询操作,形参是密码
*/
double account::query( char* p ){
/*
*如果密码不正确,抛出异常,跳出程序
*/
if( strcmp( p , pwd ) != 0 ){
throw "invalid password" ;
}
return balance ;
}
long account::getId(){
return id ;
}
/*
*帐户帐号产生器,这是与业务无关的内部操作,私有类型;
*为了保证持久性和唯一性,通过文件来保存
*/
long account::generateId(){
//初始化帐号
long id = 0 ;
//以二进制形式打开文件
ifstream ifs( "id.dat",ios::binary );
//如果文件不存在,打开会出错。这时候应该创建文件
if( ifs.fail() ){
long temp = id + 1 ;
ofstream ofs( "id.dat",ios::binary);
ofs.write( (char*)&temp,sizeof(long));
ofs.close();
return id ;
}
//打开文件成功,则读取文件内容,并将更新后的id写到文件里面
else{
ifs.read( (char*)&id,sizeof(long));
ifs.close();
long temp = id + 1 ;
ofstream ofs("id.dat",ios::binary);
ofs.write((char*)&temp,sizeof(long));
ofs.close();
return id ;
}
}
/*
*Biz类是业务类,根据业务内容的不同,该类会变化。
*该类主要负责收集用户信息,调用Account的相关方法,会根据业务的不同而不同
*/
/*
*开户操作,收集用户的名字、密码和金额,创建一个账户,
*写到文件中进行持久保存;并且告诉用户他的帐号
*/
void Biz::create(){
char name[50]; ;
char pwd[ 50 ] ;
double balance ;
cout<<"enter name >";
cin.getline( name , sizeof(name) );
cout<<"enter password>";
cin.getline( pwd , sizeof(pwd ) ) ;
cout<<"enter balance >";
cin>>balance ;
cin.ignore( 255 , '\n' );
account a( name, pwd , balance );
DA da ;
try{
da.write( a ) ;
cout<<"create account ok , id = ";
cout<<a.getId() << endl;
}catch(const char* p ){
cout<< p << endl;
}
}
/*
*保存操作,收集用户信息,修改文件内容,更新文件中的用户信息
*如果出现异常,通知用户
*/
void Biz::save(){
long id ;
double sum ;
cout<<"enter id >";
cin>>id;
cout<<"enter sum>";
cin>>sum ;
cin.ignore( 255, '\n' );
try{
DA da ;
account a = da.read( id ) ;
a.save( sum ) ;
da.update( a ) ;
cout<<"save money ok ." << endl;
}catch( const char* p ){
cout<< p << endl;
}
}
/*
*取款操作,收集用户信息,修改文件内容,更新文件中的用户信息
*如果出现异常,通知用户
*/
void Biz::withdraw(){
long id ;
char pwd[ 20 ] ;
double s ;
cout<<"enter id >";
cin>>id ;
cout<<"enter password >";
cin.ignore( 255 ,'\n' );
cin.getline( pwd , sizeof(pwd) );
cout<<"enter sum >";
cin>>s ;
cin.ignore( 255 , '\n' );
try{
DA da ;
account a = da.read( id ) ;
a.withdraw( pwd , s ) ;
da.update( a ) ;
cout<<"withdraw ok "<<endl;
}catch( const char* p ){
cout<< p << endl;
}
}
/*
*查询操作,收集用户信息,返回用户帐户金额
*如果出现异常,通知用户
*/
void Biz::query(){
long id ;
char pwd[ 50 ] ;
cout<<"enter id >";
cin>>id ;
cin.ignore( 255 , '\n' );
cout<<"enter password >";
cin.getline( pwd , sizeof( pwd ) ) ;
try{
DA da ;
account a = da.read( id ) ;
double b = a.query( pwd );
cout<<"BALANCE:" << b << endl;
}catch(const char* p ){
cout<< p << endl;
}
}
/*
*DA类负责将业务对象(Account类)进行持久化,业务不需要关注如何存储及如何持久化;
*为了体现分层的正确性,该类一定不会出现Biz类,降低耦合性,提高可复用性。
*如果需要更换存储位置,只需要改变这个类,而不用改变业务操作
*/
/*
*把账户信息从文件读到内存
*/
account DA::read(long id ){
account a ;
char name[ 100 ] ;
getNameById( id , name, sizeof(name) );
ifstream ifs( name,ios::binary );
if( ifs.fail() ){
throw "invalid id " ;
}
ifs.read((char*)&a, sizeof( a ) ) ;
ifs.close();
return a ;
}
/*
*把账户信息从内存写到文件中
*/
void DA::write( account& a ){
char name[ 50 ] ;
getNameById( a.getId() , name, sizeof(name));
ofstream ofs( name,
ios::binary );
if( ofs.fail() ){
throw "account already exist" ;
}
ofs.write( (char*)&a , sizeof( a ) ) ;
ofs.close();
}
/*
*更新账户信息,把账户信息从内存写到文件,进行覆盖
*应该还有一个查询的操作
*/
void DA::update( account& a){
char name[ 50 ];
getNameById(a.getId(),name,sizeof(name));
ofstream ofs( name,
ios::binary );
if( ofs.fail() ){
throw "No such account";
}
ofs.write( (char*)&a , sizeof( a ) ) ;
ofs.close();
}
/*
*辅助函数,根据帐户的id得到文件名称。因为文件名称是根据帐号命名的,很有规律
*/
void DA::getNameById(long id,char* p,int len ){
char* pf = "data/%d.dat";
sprintf( p , pf , id ) ;
}
参考原文:来自互联网。