开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:收支软件-面向对象方式】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9716
收支软件-面向对象方式
内容介绍
一、 目的
二、 思路分析
三、 代码实现
四、 对项目的扩展功能的练习
一、 目的:
将面向过程的代码修改成面向对象的方法,编写 myFamilyAccount.go,并使用 testMyFamilyAccount.go 去完成测试。
二、 思路分析:
1. 把记账软件的功能封装到一个结构体中,然后调用该结构体的方法,来实现记账,显示明细。结构体的名字为 FamilyAccount.
2. 在通过在 main 方法中,创建一个结构体 FamilyAccount 实例,实现记账即可。
三、 代码实现:
代码不需要重写,只需重新组织一下即可
1. 第一步思路代码实现:
familyaccount/utils/familyAccount.go
package untils
import(
“fmt”
)
type FamilyAccount struct{
//声明必须的字段
//声明一个变量,保存接受用户输入的选项
key string
//声明一个变量,控制是否退出 for
loop bool
//定义账户的余额[初始的时候预设有10000元]
balance float64
//每次收支的金额
money float64
//每次收支的说明
note string
//定义个字段,记录是否有收支行为
flag bool
//收支的详情,使用字符串来记录
//当有收支时,只需要对details进行拼接处理即可
details string
}
//编写要给工厂模式的构造方法,返回一个*FamilyAccount 实例
func NewFamilyAccount() *FamilyAccount
return &FamilyAccount{
key:””, (注:需要给出初始值)
loop:true,
balance:10000.0,
money:0.0,
note:””,(注:note 是一个说明,它的初始值为一个空的字符串)
flag:false,
details:”收支\t 账户金额\t 收支金额\t 说明”,
}
}
//将显示明细写成一个方法 (这里采用封装的办法,在后面的 switch 中显示,使得代码很整齐、很有条理)
func (this *FamilyAccount) showDetails(){
fmt.PrintIn(“-----当前收支记录-----”)
if this.flag{ (注:全部要写成this.,即用变量名进行调用)
fmt.PrintIn(this.details)
}else{
fmt.PrintIn(“当前没有收支明细...来一笔吧!”)
}
}
//将登记收入写成一个方法,和*FamilyAccount 绑定
func (this *FamilyAccount) income(){
fmt.PrintIn(“本次收入金额“)
fmt.Scanln(&this.money)
this.balance += this.money //修改账户余额
fmt.PrintIn(“本次收入说明“)
fmt.Scanln(&this.note)
//将这个收入情况拼接到 details 变量
//收入 11000 1000 有人发红包
this.details += fmt.Sprintf(“收入\t%v\t%v\t%v“,this.balance,this.money,this.note)
this.flag = true
}
//将登记支出写成一个方法,和*FamilyAccount 绑定
func (this *Familyccount) pay(){
fmt.PrintIn(“本次支出金额”)
fmt.ScanIn(&this.money)
//这里需要做一个必要的判断
if this.money > this.balance{
fmt.PrintIn(“余额的金额不足”)
//break
}
this.balance -= this.money
fmt.PrintIn(“本次支出说明”)
fmt.ScanIn(&this.note)
this.details += fmt.Sprintf(“\n 支出\t%v\t%v\t%v“,this.balance,this.money,this.note)
this.flag = true
}
//将退出系统写成一个方法,和*FamilyAccount 绑定
func (this *Familyccount) exit(){
fmt.PrintIn(“你确定要退出吗?y/n“)
choice :=””
for{
fmt.ScanIn(&choice)
if choice == “y”|| choice == “n”{
break
}
fmt.PrintIn(“你的输入有误,请重新输入 y/n”)
}
if choice == “y”{
this.loop=false
}
}
//给该结构体绑定相应的方法
//显示主菜单
func (this *FamilyAccount)MainMenu(){
for{
fmt.Println(“\n-----家庭收支记账软件-----”)
fmt.Println(“1 收支明细”)
fmt.Println(“2 登记收入”)
fmt.Println(“3 登记支出”)
fmt.Println(“4 退出软件”)
fmt.Println(“请选择(1-4)”)
fmt.Scanln(&this.key) (注:全部同步成 this. )
switch this.key{
case”1”: (注:接应上面的封装,使代码变简洁)
this.showDetails()
case”2”:
this.income()
case”3”:
this.pay()
case”4”:
this.exit()
default:
fmt.PrintfIn(“请输入正确的选项”)
}
if !this.loop{
break
}}}
2. 第二步思路代码实现:
familyaccount/main/main.go
package main
import(
"go_code/familyaccount/utils"
“fmt”
)
func main(){
fmt.PrintIn("这个是面向对象的方式完成~~”)
utils.NewFamilyAccount().MainMenu()//思路非常清晰
}
(注:这里先创建了一个 FamilyAccount 结构体的指针实例,然后再调用 MainMenu,然后调用这个结构体里的各种方法)
总结:
把所有的字段封装到一个结构体里面,然后把相应的方法在结构体里面进行绑定,最后提供 FamilyAccount 工厂模式的构造方法,然后返回一个实例,最后在 main 里面调用菜单。
3. 面向对象的好处:
(1)原来的方法都写在一个 main 对象里面,如果功能复杂的话代码会显得很乱;而现在的方法是创建一个结构体,然后把各种方法都封装到这个结构体里面,非常清晰,输不同的数字调用不同的方法。
(2)面向对象的方法可以进行分工处理,每个人写一个结构体,大大提高工作效率
四、 对项目的扩展功能的练习:
1. 对上面的项目完成转账功能;
2. 在使用该软件前,有一个登录功能,只有正确的用户名和密码才能操作。