【C++】C++应用案例-dolphin海豚记账本

目录

一、整体介绍

1.1、需求和目标

1.2、整体功能描述

二、页面及功能描述

2.1 主菜单

2.2 记账菜单

2.3 查询菜单

2.4 退出功能

三、流程设计

3.1 主流程

3.2 记账操作流程

3.3 查询操作流程

四、代码设计

4.1 核心思路

4.2 项目文件分类设计

4.2.1 头文件

4.2.2 源文件

4.2.3 代码实现步骤

4.3 代码具体实现

4.3.1 定义头文件

4.3.2 实现主体流程    

4.3.3 绘制菜单

4.3.4 读取键盘输入

4.3.5 实现具体操作功能


一、整体介绍

1.1、需求和目标

        项目的需求,实现一个叫做“海豚记账簿”的基于命令行界面的家庭记账软件。

        我们的目标,是通过项目练习,初步掌握编写软件的方法和技巧。

1.2、整体功能描述

        这个软件相对简单,只需要基于命令行做纯文本的交互,不涉及图形化界面。作为一个记账软件,主要有两大功能:记账和查询。也就是说,软件需要能够记录家庭中的每一笔收入、支出的账目,并提供查询收支明细的功能。而且为了让软件有真正的实用价值,需要对数据做持久保存:我们这里只需要存放在一个指定的文本文件中。

        项目采用分级菜单方式,每一级菜单应该有“返回主菜单”功能;主菜单有“退出”选项。

二、页面及功能描述

2.1 主菜单

        运行软件后首先应该显示主菜单。主菜单提供三个选项:“记账”、“查询”和“退出”,并在下方提示用户输入1-3的数字,选择不同的功能。

主菜单界面如下:

2.2 记账菜单

        在主菜单页面选择“1”,可以进入记账菜单(二级菜单)。记账菜单提供三个选项:“收入”、“支出”和“返回主菜单”;并在下方提示用户按对应的数字进行功能选择。

记账菜单界面如下:

        在记账菜单页面选择“1”,可以记录一笔收入账目。账目信息包括:类型(收入/支出)、金额、备注。这里需要提示用户输入账目的金额和备注信息,然后显示完成记账。

        类似地,在记账菜单页面选择“2”,可以记录一笔支出账目。提示用户输入账目的金额和备注信息,然后显示完成记账。

2.3 查询菜单

        在主菜单页面选择“2”,可以进入查询菜单。查询菜单提供四个选项:“统计所有账目”、“统计收入”、“统计支出”和“返回主菜单”;并在下方提示用户按对应的数字进行功能选择。

查询菜单界面如下:

        在查询菜单页面,选择“1”可以查询所有账目;选择“2”可以查询所有收入;选择“3”可以查询所有支出。用户选择之后,除了应该显示对应的账目明细外,还应该对所有账目进行统计汇总。

        对应地,选择“1”之后列出所有账目,统计的是总收支;选择“2”之后列出所有收入,统计总收入;选择“3”之后列出所有支出,统计总支出。

2.4 退出功能

        在主菜单页面,选择“3”可以退出软件。页面将做确认退出的对话提醒:如果用户输入“Y”则退出,输入“N”则返回主菜单页面。

三、流程设计

3.1 主流程

3.2 记账操作流程

3.3 查询操作流程

四、代码设计

4.1 核心思路

        记账软件处理的数据,就是收入或者支出的“账目”。每一条账目数据,都应该包含收支类型、金额、备注三部分,这可以构建一个结构体类型 AccountItem 来表示。

        而程序运行的开始,应该读取保存在文件中的数据,读取之后应该是一个 AccountItem 类型的数组。

        在流程控制方面,如果用户不选择退出,程序就不会结束,所以应该用一个while循环来处理整个流程;当用户确认退出时,更改一个标志位,用来退出循环。

        每一级菜单做键盘选择后,可以用 switch 分支语句来处理;不同的功能模块,可以包装成函数。

4.2 项目文件分类设计

4.2.1 头文件

        对于一个C++项目来说,构建整体架构很重要的一步就是定义头文件。一般我们会把全局变量、函数声明、以及结构体的定义都放在头文件中。

本项目可以设计两个头文件,来管理不同的内容:

  1. 结构体 AccountItem 的定义,以及涉及到账目操作的函数声明,都可以放在一个头文件 account_item.h 中;
  2. 其它一些通用的设置和功能性函数,可以放在另一个头文件common.h 中

4.2.2 源文件

真正的代码实现都放在源文件中。根据不同的用途,项目中可以用四个源文件来实现对应的功能

  1. 主体代码可以放在一个源文件 dolphin_acount.cpp 中
  2. 绘制菜单的函数都放在menus.cpp中
  3. 通用函数(比如读取键盘输入)放在read_input.cpp中
  4. 针对账目的所有操作函数(比如记账、查询)全部放在operations.cpp中

4.2.3 代码实现步骤

1、实现整体框架和主题流程

  • 在头文件account_item.h中定义好结构体;在common.h 中定义通用配置
  • 在源文件dolphin_acount.cpp的主函数中,参照主流程图实现主体流程

2、填充具体功能

  • 在menus.cpp中定义绘制各级菜单的函数;函数声明放在common.h里
  • 在read_input.cpp中定义读取键盘输入的函数,包括读取菜单选择、读取输入的金额数、读取确认退出信息;这些函数都需要对输入做合法性校验,并返回正确的值;函数声明放在common.h里
  • 在operations.cpp中定义从文件加载数据、记账、查询对应的函数。

3、各功能的细分

1)记账功能

  • 首先需要读取键盘输入的金额和备注信息;
  • 然后将其保存在一个AccounItem对象中,并添加到vector,同时写入文件

2)查询功能

  • 需要用for循环遍历整个vector
  • 通过条件筛选需要的账目打印输出,并统计总和

3)退出功能

  • 提示用户确认退出
  • 用户确认后,更改循环标志位,退出循环

4.3 代码具体实现

4.3.1 定义头文件

        首先可以在common.h中,引入相应的库,定义出需要的全局变量,以及声明绘制菜单和读取键盘输入的通用函数。通用设置,通用功能性函数声明。

#pragma once
//通用设置,通用功能性函数声明
#include<iostream>			//输入输出
#include<string>			//字符串操作
#include<fstream>			//文件操作
#include<vector>
using namespace std;

#define INCOME "收入"
#define EXPAND "支出"
#define FILENAME "AccountBook.txt"


//通用功能性函数声明
//绘制菜单的函数
void showMainMenu();
void showAccountingMenu();
void showQueryMenu();

//读取键盘输入进行合法性校验的函数
char readMenuSelection(int options);
char readQuitConfirm();
int readAmount();

        然后在account_item.h定义核心数据结构:结构体 AccountItem ,并声明涉及到账目操作的函数。结构体定义,涉及账目操作的函数声明。

#pragma once
//结构体定义,涉及账目操作的函数声明
#include "common.h"


//定义结构体类型
struct AccountItem {
	string itemType;
	int amount;		//金额
	string detail;	//备注信息
};


//针对账目数据进行操作的函数声明

//加载账目数据
void loadDataFromFile(vector<AccountItem>& items);

//	记账
void accounting(vector<AccountItem>& items);
void insertIntoFile(const AccountItem& item);
void expand(vector<AccountItem>& items);
void income(vector<AccountItem>& items);

// 查询
void query(const vector<AccountItem>& items);
void queryItems(const vector<AccountItem>& items);
void queryItems(const vector<AccountItem>& items, const string itemType);
void printItem(const AccountItem& item);

4.3.2 实现主体流程    

在源文件 dolphin_acount.cpp 的主函数中,参照主流程图实现主体流程。

代码如下:

//主体代码
#include "account_item.h"
#include "common.h"

int main() {
	
	//1、加载文件中的账目数据
	vector<AccountItem> items;
	loadDataFromFile(items);

	bool quit = false;
	while (!quit) {			
		//2、显示主菜单
		showMainMenu();
		
		//3、读取主菜单键盘选择,并做合法性校验
		char key = readMenuSelection(3);

		switch (key) {
		case '1':		//1、记账
			showAccountingMenu();	//记账显示菜单
			accounting(items);		//记账功能函数
			break;

		case '2':		//2、查询
			showQueryMenu();		//查询显示菜单 
			query(items);			//查询功能函数
			break;
			
		case '3':		//3、退出
			cout << "\n确认退出?  (Y/N):";
			if (readQuitConfirm() == 'Y')
				quit = true;
			break;

		default:
			break;
		}
	}

}

4.3.3 绘制菜单

menus.cpp 中定义绘制各级菜单的函数;对应的函数声明放在 common.h里。

代码如下:

//菜单函数
#include "common.h"

//绘制主菜单
void showMainMenu() {
	system("cls");		//清屏
	cout << "-------------------------------------------------------" << endl;
	cout << "|================ 欢迎使用海豚记账簿 =================|" << endl;
	cout << "|                                                     |" << endl;
	cout << "|***************     1 记  账     ********************|" << endl;
	cout << "|***************     2 查  询     ********************|" << endl;
	cout << "|***************     3 退  出     ********************|" << endl;
	cout << "|_____________________________________________________|" << endl;

	cout << "\n请选择(1 - 3):";
}

//绘制记账菜单
void showAccountingMenu() {
	cout << "-------------------------------------------------------" << endl;
	cout << "|===============   选择记账种类   ====================|" << endl;
	cout << "|                                                     |" << endl;
	cout << "|***************    1 收  入      ********************|" << endl;
	cout << "|***************    2 支  出      ********************|" << endl;
	cout << "|***************    3 返回主菜单  ********************|" << endl;
	cout << "|_____________________________________________________|" << endl;

	cout << "\n请选择(1 - 3):";

}

//绘制查询菜单
void showQueryMenu(){
	cout << "-------------------------------------------------------" << endl;
	cout << "|===============   选择查询条件   ====================|" << endl;
	cout << "|                                                     |" << endl;
	cout << "|***************  1 统计所有账目  ********************|" << endl;
	cout << "|***************  2 统 计 收 入   ********************|" << endl;
	cout << "|***************  3 统 计 支 出   ********************|" << endl;
	cout << "|***************  4 返回主菜单    ********************|" << endl;
	cout << "|_____________________________________________________|" << endl;

	cout << "\n请选择(1 - 4):";

}

4.3.4 读取键盘输入

        在 read_input.cpp 中定义读取键盘输入的函数,包括读取菜单选择、读取输入的金额数、读取确认退出信息;这些函数都需要对输入做合法性校验,并返回正确的值。

代码如下:

//读取输入函数
#include "account_item.h"
#include "common.h"


//读取键盘输入的菜单选项,进行合法性校验
char readMenuSelection(int options) {
	string str;

	while (true)
	{
		getline(cin, str);
		//进行合法化校验
		if (str.size() == !1 || str[0] - '0' <= 0 || str[0] - '0' > options)
			cout << "输入错误,请重新选择:";
		else
			break;
	}

	//输入合法
	return str[0];

}


//读取确认退出信息,并进行合法性校验
char readQuitConfirm() {
	string str;
	while (true)
	{
		getline(cin, str);
		//进行合法性校验
		if (str.size() != 1 || toupper(str[0]) != 'Y' && toupper(str[0]) != 'N') 
			cout << "输入错误,请重新选择:";
		else
			break;
	}
	//输入合法
	return toupper(str[0]);
}

//读取键盘输入的金额数,并做合法性校验
int readAmount() {
	int amount;

	string str;
	while (true)
	{
		getline(cin, str);
		//进行合法性校验
		try
		{
			amount = stoi(str);
			break;
		}
		catch (invalid_argument e)
		{
			cout << "输入错误,请正确输入数字:";
		}
	}
	//输入合法
	return amount;
}

4.3.5 实现具体操作功能

     在 operations.cpp 中,定义从文件加载数据、记账、查询等操作对应的函数。

  1. (1)从文件加载数据

loadDataFromFile():逐行读取文件中数据,按空格将每个词赋值给AccountItem中的每个成员,得到一个AccountItem对象,并把它保存到数组中。

由于数组长度是固定的,这里应该用可变长的容器对象vector<AccountItem>来保存;为了能够在函数中修改vector,应该把它的引用作为函数参数传入。

  1. (2)记账功能

        首先需要读取键盘输入的金额和备注信息;然后将其保存在一个AccountItem 对象中,并添加到数组,同时写入文件。

accounting():记账主体函数

income():记录一笔收入,将数据添加到vector中,并调用insertIntoFile()函数,写入文件做持久化保存

expand():记录一笔支出,将数据添加到vector中,并调用insertIntoFile()函数,写入文件做持久化保存

insertIntoFile():将一条账目写入文件中。

  1. (3)查询功能

        需要用for循环遍历整个数组,通过条件筛选需要的账目打印输出,并统计总和。

query():查询主体函数

queryItems():查询账目功能函数,遍历所有账目,统计总收支。

具体代码如下:

//涉及账目操作的函数
#include "account_item.h"
#include "common.h"


//读取文件中的账目数据
void loadDataFromFile(vector<AccountItem>& items) {
	ifstream input(FILENAME);

	//逐行读取每一条数据,包装成AccountItem对象
	AccountItem item;
	string line;
	while (input>>item.itemType>>item.amount>>item.detail) {
		items.push_back(item);
	}

	input.close();
}

//--------------------------------1、记账----------------------------------------------------------
//记账操作
void accounting(vector<AccountItem>& items) {
	//读取键盘选择,并做合法化校验
	char key = readMenuSelection(3);

	switch (key)
	{
	case '1':		//1、收入
		income(items);
		break;
	case '2':		//2、支出
		expand(items);
		break;
	case '3':		//3、返回主菜单
		break;

	default:
		break;
	}
}

//记录一笔收入
void income(vector<AccountItem>& items) {
	//新构建一个AccountItem对象
	AccountItem item;

	//类型已经确定,就是收入
	item.itemType = INCOME;

	//与用户交互,键盘输入金额和备注信息
	cout << "\n本次收入金额:";
	item.amount = readAmount();

	cout << "\n备注:";
	getline(cin, item.detail);

	//添加到vector中
	items.push_back(item);
	//写入文件做持久化保存
	insertIntoFile(item);
	//显示成功信息
	cout << "\n------------------记账 成功!------------------\n";
	cout << "\n请按回车键返回主菜单......" << endl;

	string str;
	getline(cin, str);
}
//记录一笔支出
void expand(vector<AccountItem>& items) {
	//新构建一个AccountItem对象
	AccountItem item;

	//类型已经确定,就是收入
	item.itemType = EXPAND;

	//与用户交互,键盘输入金额和备注信息
	cout << "\n本次支出金额:";
	item.amount = -readAmount();

	cout << "\n备注:";
	getline(cin, item.detail);

	//添加到vector中
	items.push_back(item);
	//写入文件做持久化保存
	insertIntoFile(item);
	//显示成功信息
	cout << "\n------------------记账 成功!------------------\n";
	cout << "\n请按回车键返回主菜单......" << endl;

	string line;
	getline(cin, line);
}
//将一条账目写入文件中
void insertIntoFile(const AccountItem& item) {
	//创建一个ofstream对象,第二个参数表示以追加的方式进行写入
	ofstream output(FILENAME, ios::out | ios::app);

	output << item.itemType << "\t" << item.amount << "\t" << item.detail << endl;
	output.close();
}

//---------------------------------2、查询---------------------------------------------------
//查询操作
void query(const vector<AccountItem>& items) {
	//读取键盘选择,并做合法性校验
	char key = readMenuSelection(4);

	switch (key)
	{
	case '1':		//1、查询所有账目,并统计总收支
		queryItems(items);
		break;
	case '2':		//2、查询所有账目,并统计总收入
		queryItems(items,INCOME);
		break;
	case '3':		//3、查询所有账目,并统计总支出
		queryItems(items, EXPAND);
		break;

	default:
		break;
	}
}

//查询账目功能函数
void queryItems(const vector<AccountItem>& items) {
	cout << "--------------------查询结果-------------------------" << endl;
	cout << "\n类型\t\t金额\t\t备注\n" << endl;

	//遍历所有账目,统计总收支
	int total = 0;
	for (auto item : items) {
		printItem(item);
		total += item.amount;
	}
	//输出信息
	cout << "==============================================" << endl;
	cout << "总收支:" << total << endl;
	cout << "\n请按回车键返回主菜单......" << endl;

	string line;
	getline(cin, line);
}

//函数重载,查询账目功能函数
void queryItems(const vector<AccountItem>& items,const string itemType) {
	cout << "--------------------查询结果-------------------------" << endl;
	cout << "\n类型\t\t金额\t\t备注\n" << endl;

	//遍历所有账目,统计总收入或总支出
	int total = 0;
	for (auto item : items) {
		if (item.itemType != itemType) {
			continue;
		}
		printItem(item);
		total += item.amount;
	}

	//输出信息
	cout << "==============================================" << endl;
	cout << ((itemType == INCOME) ? "总收入:" : "总收入:" )<< total << endl;
	cout << "\n请按回车键返回主菜单......" << endl;


	string line;
	getline(cin, line);
}

//打印输出一条账目信息
void printItem(const AccountItem& item) {
	cout << item.itemType << "\t\t" << item.amount << "\t\t" << item.detail << endl;
}

至此,我们就完成了对海豚记账簿的设计与实现啦,你也快去试一下吧~

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache DolphinScheduler (海豚调度)是一个开源的大数据分布式工作流、任务调度系统,属于Apache基金会孵化器项目。DolphinScheduler能够支持Hadoop、Spark、Flink、Storm、Hive等大数据生态系统中的常用计算框架,支持Docker、Shell、Python等常用脚本语言。其最新版本为3.1.3。 该版本在上一个版本的基础上进行了多项升级和改进,包括: 1.添加了对Docker Compose的支持: 用户可以在调度任务时使用Docker Compose打包和运行任务。 2.Planner-Dynamic算法升级: Planner-Dynamic算法可以根据任务执行延迟等不同因素进行动态调整,从而提高任务的执行效率和稳定性。 3.增加了任务执行状态监控: 用户可以实时查看任务执行的状态,包括任务的进度、日志和结果等。 4.优化了任务失败重试机制: DolphinScheduler增加了任务失败重试机制,可以自动重试失败的任务,从而提高系统的稳定性和可靠性。 5.增加了多个Web UI支持: DolphinScheduler增加了多个Web UI页面,包括对任务执行状态监控和调度任务等功能的支持,提供了更加易于使用的用户界面。 6.优化了系统性能和稳定性: DolphinScheduler针对上一个版本中的一些问题进行了优化和改进,包括系统的性能、稳定性和可扩展性等方面。 综上所述,Apache DolphinScheduler 3.1.3版本在功能、性能、稳定性和易用性等方面得到了多项升级和改进,在大数据分布式任务调度和工作流领域具有广泛的应用前景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值