目录
1.引出
近期学习go语言,接触到了面向对象问题,在课程指导下,写一个利用Go面向对象过程编写家庭收支记账软件。
2.需求
我们要利用面向对象来编写,并且要让项目有显示明细,登记收入,登记支出功能,并且对这些功能尽可能的是其各方面满足。
3.代码实现
1.结构体的定义
既然我们要实现面向对象,那么就需要结构体来进行方法的调用,那么我们就是需要结构体来绑定各种方法。
type FamilyAccount struct {
//申明字段
//用key来表示进入的功能
key string
//用loop来判断是否退出
loop bool
//定义账户余额
balance float64
//定义收支的资金数
money float64
//定义变量,记录是否有收支的行为
flag bool
//定义资金的说明
note string
details string
}
2.对结构体进行赋值函数
既然我们声明了结构体,那我们在这个运行的过程中,就是需要对结构体进行一些初始的赋值。这个时候我们就利用一个函数,进行赋值的操作。
func NewFamilyAccount() *FamilyAccount {
return &FamilyAccount{
key: "",
loop: true,
balance: 1000.0,
money: 0.0,
note: "",
flag: false,
details: "收支\t账户金额\t收支金额\t说 明",
}
}
3.将功能便写成方法
我们可以利用结构体绑定方法的例子,帮助我们进行功能的实现。
1.显示明细
在显示明细的时候我们加入了一些细节,必然在没有进行收支的操作时,我们是没有明细的,所以会打印出来一些不一样的东西。
// 将显示明细写成方法
func (this *FamilyAccount) ShowDetails() {
//进行判断
if this.flag == true {
fmt.Println("------------------收支明细------------------")
fmt.Println(this.details)
} else {
fmt.Println("没有收支的行为")
}
}
2.登记收入
我们在进行收入和支出操作的时候,需要进行字符串的拼接,所以这里我们要说一下fmt.Sprintf()
fmt.Sprintf("%v_%s",entId,visitorName)
比如entId 是interface{} 类型 , visitorName是字符串类型
格式化样式:字符串形式,格式化动词以%开头。
参数列表:多个参数以逗号分隔,个数必须与格式化样式中的个数一一对应,否则运行时会报错。
// 将登记收入写成方法
func (this *FamilyAccount) Income() {
fmt.Println("------------------登记收入------------------")
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
}
3.登记支出
进行支出的时候,我们首先要判断我们的余额里面有没有足够的金额,如果没有,那么就返回,如果有的话我们也还是要进行字符串的拼接操作。
// 将支出写成方法
func (this *FamilyAccount) Pay() {
fmt.Println("------------------登记支出------------------")
fmt.Println("本次支出金额:")
fmt.Scanln(&this.money)
if this.money > this.balance {
fmt.Println("资金余额不足")
}
//资金进行改变
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
}
4.退出程序
在退出程序的时候我们进行误操的判断,进行二次判断,这样对于操作的执行性更好。
// 将退出写成方法
func (this *FamilyAccount) Exit() {
//进行是否退出的判断
fmt.Println("您确定要退出嘛?y/n")
choice := ""
for {
//输入判断的方法
fmt.Scanln(&choice)
if choice == "y" || choice == "n" {
break
}
fmt.Println("您的输入有误,请重新输入")
}
if choice == "y" {
this.loop = false
}
fmt.Println("------------------退出软件------------------")
}
4.显示主菜单
在显示主菜单的时候我们利用的是switch,
// 给结构体绑定相应方法
// 显示主菜单
func (this *FamilyAccount) MainMenu() {
for {
fmt.Println("------------------家庭收支记账软件------------------")
fmt.Println(" 1.收支明细")
fmt.Println(" 2.登记收入")
fmt.Println(" 3.登记支出")
fmt.Println(" 4.退出软件")
fmt.Println("请选择1——4:")
fmt.Scanln(&this.key)
//利用switch进行选择
switch this.key {
case "1":
this.ShowDetails()
case "2":
this.Income()
case "3":
this.Pay()
case "4":
this.Exit()
default:
fmt.Println("请输入正确的选项...")
}
if !this.loop {
break
}
}
}
2.总结
我们上面利用面向对象的方法,对这个软件进行模块化,使很多的东西更加细节,这样使得我们的代码有更好的可读性,这样逐渐下来,使得我们在后续的很多增加功能的作用中,让我们可以很好的操作。接下来,我们看一下整体的代码。
这里面有个很重要的地方需要单独来说。
func main() {
//进行面向对象的方式完成
//NewFamilyAccount().MainMenu()//这个是我们的函数直接返回一个结构体指针类型,
//这样直接接可以调用他的方法
a := NewFamilyAccount()//其实上面的方法他是等同于下面的,我们可以看出,这个返回给啊,
a.MainMenu()//然后在a中调用方法
}
这个是比较重要的,我们必须要了解两种方法,明白第一种方法的底层实现,这里并不是函数调用方法,而是这个函数的函数值可以调用他的方法。这样就可以很好的简明代码。
package main
import "fmt"
type FamilyAccount struct {
//申明字段
//用key来表示进入的功能
key string
//用loop来判断是否退出
loop bool
//定义账户余额
balance float64
//定义收支的资金数
money float64
//定义变量,记录是否有收支的行为
flag bool
//定义资金的说明
note string
details string
}
// 对结构体进行赋初始值
func NewFamilyAccount() *FamilyAccount {
return &FamilyAccount{
key: "",
loop: true,
balance: 1000.0,
money: 0.0,
note: "",
flag: false,
details: "收支\t账户金额\t收支金额\t说 明",
}
}
// 将显示明细写成方法
func (this *FamilyAccount) ShowDetails() {
//进行判断
if this.flag == true {
fmt.Println("------------------收支明细------------------")
fmt.Println(this.details)
} else {
fmt.Println("没有收支的行为")
}
}
// 将登记收入写成方法
func (this *FamilyAccount) Income() {
fmt.Println("------------------登记收入------------------")
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
}
// 将支出写成方法
func (this *FamilyAccount) Pay() {
fmt.Println("------------------登记支出------------------")
fmt.Println("本次支出金额:")
fmt.Scanln(&this.money)
if this.money > this.balance {
fmt.Println("资金余额不足")
}
//资金进行改变
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
}
// 将退出写成方法
func (this *FamilyAccount) Exit() {
//进行是否退出的判断
fmt.Println("您确定要退出嘛?y/n")
choice := ""
for {
//输入判断的方法
fmt.Scanln(&choice)
if choice == "y" || choice == "n" {
break
}
fmt.Println("您的输入有误,请重新输入")
}
if choice == "y" {
this.loop = false
}
fmt.Println("------------------退出软件------------------")
}
// 给结构体绑定相应方法
// 显示主菜单
func (this *FamilyAccount) MainMenu() {
for {
fmt.Println("------------------家庭收支记账软件------------------")
fmt.Println(" 1.收支明细")
fmt.Println(" 2.登记收入")
fmt.Println(" 3.登记支出")
fmt.Println(" 4.退出软件")
fmt.Println("请选择1——4:")
fmt.Scanln(&this.key)
//利用switch进行选择
switch this.key {
case "1":
this.ShowDetails()
case "2":
this.Income()
case "3":
this.Pay()
case "4":
this.Exit()
default:
fmt.Println("请输入正确的选项...")
}
if !this.loop {
break
}
}
}
func main() {
//进行面向对象的方式完成
//NewFamilyAccount().MainMenu()
a := NewFamilyAccount()
a.MainMenu()
}