19、做中学 | 初升高 | 考场二 | 面向对象-家庭收支记账软件

王者杯·14天创作挑战营·第8期 10w+人浏览 147人参与

上场考试,根据思路进行了面向过程编写,本篇引导为:面向对象编写

还记得对象是由什么组成的吗?属性,方法

一、需求讨论

实现一个“控制台版家庭收支记账软件”的业务核心逻辑,用结构体封装账户数据和操作方法,支持循环显示菜单,让用户可以反复进行:

  1. 查看收支明细
  2. 登记收入
  3. 登记支出
  4. 退出软件(带二次确认)

1. 菜单

使用 for { … } 无限循环,并根据退出变量进行中断循环。
每轮循环打印菜单:

  1. 收支明细
  2. 登记收入
  3. 登记支出
  4. 退出软件

2. 登记收入

记录一次收入操作,并更新余额与明细。

3. 登记支出

记录一次支出操作,并更新余额与明细,且要校验余额是否足够。

4. 退出软件

让用户确认是否退出主菜单循环(包含二次确认)。

二、面向对象

1. 封装属性

根据需求我们确定一些属性,并进行封装到结构体中

// MyFamilyAccountingTest 创建结构体 声明属性
type MyFamilyAccountingTest struct {
	// 输入选项值
	key string
	// 是否退出
	loop bool

	// 定义账户余额
	balance float64
	// 定义收支金额
	money float64
	// 描述
	note string
	// 收支详情
	details string

	// 确定要退出吗
	choice string
	// 收支行为
	flag bool
}

并根据这些属性进行工厂模式,初始化属性,并返回对象指针

// NewMyFamilyAccountingTest 通过工厂模式,进行初始化结构体属性
func NewMyFamilyAccountingTest() *MyFamilyAccountingTest {
	return &MyFamilyAccountingTest{
		key:     "",
		loop:    false,
		balance: 10000.0,
		money:   0.0,
		note:    "",
		details: "收支\t账户金额\t收支金额\t说    明",
		choice:  "",
		flag:    false,
	}
}

2. 菜单方法

进行绑定菜单方法到家庭账户结构体上,方法功能为用户提供选项,并获取选项,进行跳转到对应的功能

// ShowMenu 菜单
func (this *MyFamilyAccountingTest) ShowMenu() {
	// 一个程序不可能只用一次,进行多次,所以使用for循环
	for {
		fmt.Println("---------------------家庭收支记账软件---------------------")
		fmt.Println("                       1 收支明细")
		fmt.Println("                       2 登记收入")
		fmt.Println("                       3 登记支出")
		fmt.Println("                       4 退出软件")
		fmt.Print("请选择(1-4):")
		fmt.Scanln(&this.key)
		switch this.key {
		case "1":
			this.ShowDetails()
		case "2":
			this.Income()
		case "3":
			this.Pay()
		case "4":
			this.Outcome()
		default:
			fmt.Println("请输入正确选项")
		}

		// 如果退出,则结束循环
		if this.loop {
			break
		}
	}
}

3. 收支明细

根据菜单定义的方法,进行编写收支明细

// ShowDetails 显示收支明细
func (this *MyFamilyAccountingTest) ShowDetails() {
	if this.flag {
		fmt.Println("-----------当前收支明细记录-----------")
		fmt.Println(this.details)
	} else {
		fmt.Println("当前没有收支明细")
	}
}

4. 登记收入

获取用户的信息,并更新到变量中

// Income 收支
func (this *MyFamilyAccountingTest) Income() {
	fmt.Println("本次收入金额:")
	fmt.Scanln(&this.money)
	this.balance += this.money

	fmt.Println("本次收入说明:")
	fmt.Scanln(&this.note)
	this.details += fmt.Sprintf("\n收入\t%v\t%v\t%v", this.balance, this.money, this.note)
	this.flag = true
}

5. 登记支出

获取用户,进行判断支出金额是否超出余额,并信息更新变量

// Pay 支出
func (this *MyFamilyAccountingTest) Pay() {
	fmt.Println("本次支出金额:")
	fmt.Scanln(&this.money)

	// 判断支出是否超出
	if this.money > this.balance {
		fmt.Println("余额不足")
		return
	}
	this.balance -= this.money

	fmt.Println("本次支出说明:")
	fmt.Scanln(&this.note)
	this.details += fmt.Sprintf("\n支出\t%v\t%v\t%v", this.balance, this.money, this.note)
	this.flag = true
}

6. 退出

引导用户进行二次确认,并跳出循环

// Outcome 退出
func (this *MyFamilyAccountingTest) Outcome() {
	fmt.Println("你确定要退出吗?y/n")
	for {
		fmt.Scanln(&this.choice)
		if this.choice == "y" || this.choice == "n" {
			break
		}
		fmt.Println("你的输入有误,你重新输入 y/n")
	}
	if this.choice == "y" {
		this.loop = true
	}
}

没有细致划分对象,这里只是单纯的使用了家庭账户余额结构体


common包下,MyFamilyAccountingTest结构体

package common

import "fmt"

// MyFamilyAccountingTest 创建结构体 声明属性
type MyFamilyAccountingTest struct {
	// 输入选项值
	key string
	// 是否退出
	loop bool

	// 定义账户余额
	balance float64
	// 定义收支金额
	money float64
	// 描述
	note string
	// 收支详情
	details string

	// 确定要退出吗
	choice string
	// 收支行为
	flag bool
}

// NewMyFamilyAccountingTestTest 通过工厂模式,进行初始化结构体属性
func NewMyFamilyAccountingTest() *MyFamilyAccountingTest {
	return &MyFamilyAccountingTest{
		key:     "",
		loop:    false,
		balance: 10000.0,
		money:   0.0,
		note:    "",
		details: "收支\t账户金额\t收支金额\t说    明",
		choice:  "",
		flag:    false,
	}
}

// ShowMenu 菜单
func (this *MyFamilyAccountingTest) ShowMenu() {
	// 一个程序不可能只用一次,进行多次,所以使用for循环
	for {
		fmt.Println("---------------------家庭收支记账软件---------------------")
		fmt.Println("                       1 收支明细")
		fmt.Println("                       2 登记收入")
		fmt.Println("                       3 登记支出")
		fmt.Println("                       4 退出软件")
		fmt.Print("请选择(1-4):")
		fmt.Scanln(&this.key)
		switch this.key {
		case "1":
			this.ShowDetails()
		case "2":
			this.Income()
		case "3":
			this.Pay()
		case "4":
			this.Outcome()
		default:
			fmt.Println("请输入正确选项")
		}

		// 如果退出,则结束循环
		if this.loop {
			break
		}
	}
}

// ShowDetails 显示收支明细
func (this *MyFamilyAccountingTest) ShowDetails() {
	if this.flag {
		fmt.Println("-----------当前收支明细记录-----------")
		fmt.Println(this.details)
	} else {
		fmt.Println("当前没有收支明细")
	}
}

// Income 收支
func (this *MyFamilyAccountingTest) Income() {
	fmt.Println("本次收入金额:")
	fmt.Scanln(&this.money)
	this.balance += this.money

	fmt.Println("本次收入说明:")
	fmt.Scanln(&this.note)
	this.details += fmt.Sprintf("\n收入\t%v\t%v\t%v", this.balance, this.money, this.note)
	this.flag = true
}

// Pay 支出
func (this *MyFamilyAccountingTest) Pay() {
	fmt.Println("本次支出金额:")
	fmt.Scanln(&this.money)

	// 判断支出是否超出
	if this.money > this.balance {
		fmt.Println("余额不足")
		return
	}
	this.balance -= this.money

	fmt.Println("本次支出说明:")
	fmt.Scanln(&this.note)
	this.details += fmt.Sprintf("\n支出\t%v\t%v\t%v", this.balance, this.money, this.note)
	this.flag = true
}

// Outcome 退出
func (this *MyFamilyAccountingTest) Outcome() {
	fmt.Println("你确定要退出吗?y/n")
	for {
		fmt.Scanln(&this.choice)
		if this.choice == "y" || this.choice == "n" {
			break
		}
		fmt.Println("你的输入有误,你重新输入 y/n")
	}
	if this.choice == "y" {
		this.loop = true
	}
}

测试程序入库MyFamilyAccountingDemo

package main

import "learn_golang_project/src/go_code/common"

func main() {
	common.NewMyFamilyAccountingTest().ShowMenu()
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值