前言
文章灵感源自于好兄弟的求助。好兄弟让我写一个 ATM 模拟程序来和他的对比一下。
从 OI 层面来看,这不就是纯纯的中等模拟吗?直接启洞!
设计
分析
我们先来看看要求:
ATM模拟程序能够完成ATM的主要功能,包括:
①显示欢迎词及提示信息;
②用户插卡,ATM验证用户账号及密码有效性,输入错误3次即被锁卡;
③余额查询:初始余额为10000元;
④取款功能:每次取款余额为100的整数倍,有单笔和单日金额限制;
⑤转账功能:可将本账户中的存款转入其它账户,转入账户账号需两次输入确认;
⑥修改密码:密码为6位数字,新密码需要两次输入确认;
⑦退卡。
设计实现命令行界面,界面应友好、方便操作。
不着急分析要求,我们再看看 ATM 机的工作流程:
插卡(进入系统)-> 登录 -> 用户操作(存取款等) ->退卡
通过分析了工作流程,我们可以发现一个简单的 ATM 机可以分为三个子系统:主界面系统、登录系统、用户端操作系统。
再回头看看设计要求,我们可以发现要求 ① 是贯穿 3 个子系统的,要求 ② 则是对于登陆系统来说的,剩下的要求都是对用户操作系统的要求,知道了这些,我们就可以开始设计程序了。
总体设计思路:使用类来实现 ATM 机的模拟。
代码
账户
首先先建立账户信息。一个账户所包含的信息有:用户名、卡号、密码、身份证号、余额、银行卡状态以及银行卡限额(和现实相似,I 类卡和 II 类卡)
使用结构体来定义这些内容,代码如下:
struct Account{
string cardid;
string user_name;
string idcard;
string password;
double money;
bool lock;
int limit;
};
卡号,身份证号,用户名可能长达十几位,因此使用 string 来存储。
密码固定六位,方便判断也用了 string 。(用 int 其实也可以)
钱可能会出现小数,所以我们使用 double 类型。
lock 表示银行卡状态。0为未锁卡,1为锁卡。
limit 表示限额。
主界面
我们首先使用 类 来定义 ATM 系统
class ATMsystem {
public:
vector<Account> accountlist; //银行账户存储,方便查找
const int once_limit = 1e9+7; //一次的限额,为了方便就这样定义了
}atm;
接下来是写主界面系统,我们命名为 sys (防止和system函数重名)
主界面比较容易,就是一个按钮对应一个操作,一个操作对应一个函数。
void sys(){
while(1) {
clear();
cout<<"=============== ATM 系统 ==============="<<endl;
cout<<"欢迎使用 ATM 机!请选择你要操作的类型"<<endl;
cout<<"1、银行开户\n2、用户登录\n3、退出系统"<<endl;
cout<<"按5可获取帮助"<<endl;
int op;
while( 1 ) {
cin >> op;
if( op == 0 ) op = 3;
if(op == 1 || op == 2 || op == 3 || op == 4 || op == 5 ) break;
cout << "操作错误!请重新输入" << endl;
}
if(op==1) {
clear();
add();
}
else if(op==2) {
int record = login();
//if( record != -1 ) { cout<<record<<"\n";system("pause");/*cout<<accountlist[record].money<<'\n';*/}
if( record != -1 ) user_command( accountlist[record] );
}
else if( op == 3 ) {
close();
break;
}
else if( op == 4 ) {
clear();checklist();system("pause");}
else if( op == 5 ) {
help();}
}
}
创建账户
如果用户选择了1(银行开户),就跳转到创建账户函数(命名为 add 或者 registered 均可),这里命名为 add。
创建账户需要经历以下过程:
输入姓名 -> 输入身份证号 -> 输入密码 -> 二次确认 -> 随机一个银行卡号,完成账户创建。
其中:身份证号、密码需要验证是否合法。身份证号为 18 位,密码为 6 位。
void add() {
Account user;
cout << "请输入姓名:" << endl;
cin>>user.user_name;
cout << "请输入身份证号:" << endl;
while(1) {
cin >> user.idcard;
if( user.idcard == "0" ) return ;
if( user.idcard.size()==18 ) break;
else cout<< "格式错误!请重新输入。"<< endl;
}
cout << "请输入密码" << endl;
while(1) {
cin >> user.password;
while( user.password.size() != 6 ) {
cout << "格式错误!请重新输入" << endl; cin >> user.password;}
if ( check_password( user.password ) == 1 ) {
cout << "请再次确认密码!" <<endl;
string temp;
cin >> temp;
while( temp.size() != 6 ) {
cout << "格式错误!请重新输入" << endl; cin >> temp;}
if( temp == user.password ) {
user.money = 10000 ; user.lock = 0; user.limit = 1000000;
user.cardid = id_rand();
accountlist.push_back(user);
cout << "创建账户成功!您的账户是: " << user.cardid << endl;
break;
}
}
}
cout<<accountlist.size()<<'\n';
system("pause");//暂停,方便用户记录卡号。
}
登录
如果用户选择了 2 (登录),跳转至登录系统。这里将登录系统命名为 login。
login 函数应为 int 型,以便确认是否能够登录以及返回登录账户在 accountlist 的位置。
登录系统流程:
插卡(输入卡号) -> 输入密码 -> 进入操作系统/返回主界面
这里需要注意以下几点:
- 密码输错三次马上锁卡,告知用户并返回主界面;
- 检查密码位数是否合法,不合法的密码不能算输错密码;
- 如果卡已经被上锁,告知用户并退回主界面;
- 成功登录,返回账户返回登录账户在 accountlist 的位置,否则返回 -1。(因为 vector 数组从 0 开始)
int login() {
clear();
int cnt = 0,flag; Account user;
cout << "请输入账户" << endl;
while(1) {
flag = -1; string str;
cin >> str;
if( str == "0" ) return -1;
for(int i=0;i<(int)accountlist.size();++i) {
if( accountlist[i].cardid == str ) {
user = accountlist[i];
flag = i;
break;
}
}
if( flag != -1 ) break;
else cout << "该账户不存在!请重新输入" << endl;
}
if( user.lock == 1 ) {
cout << "该银行卡以上锁,请联系银行" << endl;
return -1;
}
cout << "请输入密码" << endl;
while( cnt<3 ) {
string str;
cin >> str;
while( check_password(str) != 1 ) {
cout << "密码不合法,请重新输入" << endl;
cin >> str;
}
if( user.password == str ) {
cout << "登录成功!正在进入操作系统" << endl;
return flag;
}
cnt++;
cout << "密码错误!还有" << 3-cnt << "次机会" << endl;
}
if( cnt == 3