Chapter012 golang面向对象编程应用思想

上一章:Chapter011 golang中方法
下一章:Chapter013 golang接口

一、开发步骤

1、声明(定义)结构体,并确定结构体名
2、编写结构体字段
3、编写结构体方法

二、应用

1、

package main

import (
	"fmt"
	_ "fmt"
)

type Student struct {
	name string
	gender string
	age int
	id int
	score float64
}

func (student *Student) say()  {
	fmt.Printf("name:%v,gender:%v,id:%v,score:%v\n",student.name,student.gender,student.age,student.id,student.score)
}

func main()  {
	stu :=Student{"tom","male",18,1,100.00}
	(&stu).say()
}

在这里插入图片描述
2、

package main

import (
	"fmt"
	_ "fmt"
)

type Box struct {
	len float64
	width float64
	hight float64
}

func (box Box) volum() float64  {
	v := box.len * box.hight * box.width
	return v
}

func main()  {
	var box Box
	box.width = 1.00
	box.hight = 2.00
	box.len = 3.00
	v := box.volum()
	fmt.Printf("v=%v",v)
}

在这里插入图片描述
3、

package main

import (
	"fmt"
	_ "fmt"
)

type Visitor struct {
	Name string
	Age int
}

func (visitor *Visitor) howmuch() {
	var money float64  = 0
	if visitor.Age >60||visitor.Age<8{
		fmt.Print("请勿游玩")
	}
	if visitor.Age >18{
		money = 20
		fmt.Printf("%v",money)
	}else {
		fmt.Printf("%v",money)
	}
}

func main()  {
	var visitor Visitor
	for {
		fmt.Print("输入姓名:")
		_, _ = fmt.Scan(&visitor.Name)
		if visitor.Name == "n"{
			fmt.Print("退出\n")
			break
		}
		fmt.Print("输入年龄:")
		_, _ = fmt.Scan(&visitor.Age)
	}
	visitor.howmuch()
}
三、工厂模式

1、使用场景如下:

package model
type student struct{
	...
}

当上面结构体名是小写,但是又想在其他包里面使用到student结构体时使用工厂模式(若是大写,引包后就可以直接用了)
在这里插入图片描述

package model

type student struct {   //小写
	Name string   //大写
	score float64  //小写
}

//工厂模式

func NewStudent(n string,s float64) *student {
	return &student{   //返回student指针
		Name:  n,
		score: s,
	}
}

func (s *student) GetScore() float64  { //那么写一个对外的方法返回值就可以了
	return (*s).score
}

package main

import (
	"fmt"
	_ "fmt"
	"remoteProjects/基本语法/Chapter08/demo03/model"
	_ "remoteProjects/基本语法/Chapter08/demo03/model"
)

func main()  {
	var stu  = model.NewStudent("tom",98.8)
	fmt.Println(*stu)
	fmt.Printf("name:%v score:%v",stu.Name,stu.GetScore())
}

在这里插入图片描述

四、面向对象思想——抽象

1、将一类事物共有的属性(字段)和行为(方法)提取出来,形成一个物理模型
2、银行账户案例

package main

import (
	"fmt"
	_ "fmt"
)

type Account struct {
	Accountnum string
	Psw string
	Balance float64
}

func (account *Account) Deposite (money float64, pwd string){
	//看输入密码是否正确
	if pwd != account.Psw{
		fmt.Printf("erro password\n")
		return
	}
	if money <=0{
		fmt.Printf("error money\n")
		return
	}
	account.Balance += money
	fmt.Printf("success\n")
}

func (account *Account) Withdraw (money float64, pwd string){
	//看输入密码是否正确
	if pwd != account.Psw{
		fmt.Printf("erro password\n")
		return
	}
	if money <=0 || money>account.Balance{
		fmt.Printf("error money\n")
		return
	}
	account.Balance -= money
	fmt.Printf("success\n")
}

func (account Account) Query(pwd string)  {
	if pwd != account.Psw{
		fmt.Printf("erro password\n")
		return
	}
	fmt.Printf("你的账号余额为%v\n",account.Balance)
}
func main()  {
	account :=Account{
		Accountnum: "1",
		Psw:        "666666",
		Balance:    100,
	}
	account.Query("666666")
	account.Deposite(666,"666666")
	account.Withdraw(1000,"666666")
	account.Query("666666")
}

在这里插入图片描述

五、面向对象三大特征
1、封装

1.说明
(1)封装就是把抽象出来的字段和对字段的操作封装在一起,数据被保护在内部,程序的其他包只能通过被授权的操作(方法),才能对字段进行操作
(2)golang中封装不是很严格
例如:对电视机的操作
2.好处
(1)隐藏实现细节
(2)可以对数据进行验证,保证安全合理
3.应用
(1)对结构体中的属性进行封装
(2)通过方法,包实现封装
4.实现步骤
(1)将结构体、字段(属性)首字母进行小写,其他包就不能访问了,类似private
(2)给结构体所在包提供一个工厂模式的函数,首字母大写,类似一个构造函数
(3)提供一个首字母大写的Set方法(类似其他语言的public),用于对属性判断并赋值

func (var 结构体类型名) Setxxx(参数列表)(返回值列表){
	//加入业务判断逻辑
}

(4)提供一个首字母大写的Get方法(类似其他语言的public),用于获取属性的值

func (var 结构体类型名) GetXXX(){
	return var 字段
}

5.快速入门
(1)设计一个程序(Person.go),不能随便查看人的年龄、工资等隐私,并对输入的年龄进行合理的验证
在这里插入图片描述
main.go

package main

import (
	"fmt"
	_ "fmt"
	"remoteProjects/基本语法/Chapter08/fengzhuang/model"
	_ "remoteProjects/基本语法/Chapter08/fengzhuang/model"
)

func main()  {
	p:=model.NewPerson("smith")
	p.SetAge(110)
	p.SetSal(6000)
	fmt.Print(*p)
}

person.go

package model

import "fmt"

type person struct {
	Name string
	age int //不可直接访问
	sal float64
}

//工厂模式,相当于构造函数
func NewPerson(name string) *person {
	return &person{
		Name: name,
	}
}

//为了访问age和sal,编写一对Setxxx的方法和Getxxx的方法
func (p *person) SetAge(age int)  {
	if age >0 &&age<150{
		p.age =age
	}else {
		fmt.Printf("年龄错误\n")
	}
}

func (p *person) GetAge() int  {
	return p.age
}


func (p *person) SetSal(sal float64)  {
	if sal >3000 &&sal<30000{
		p.sal =sal
	}else {
		fmt.Printf("薪水错误\n")
	}
}

func (p *person) GetSal() float64  {
	return p.sal
}

在这里插入图片描述
(2)练习
main.go

package main

import (
	"fmt"
	_ "fmt"
	"remoteProjects/基本语法/Chapter08/fzdemo/model"
)
import _ "remoteProjects/基本语法/Chapter08/fzdemo/model"

func main()  {
	account := model.NewAccount("1")
	account.SetPwd("666666")
	account.SetBalance(1000.01)
	money :=account.GetBalance("666666")
	fmt.Printf("money=%v",money)
}

account.go

package model

import (
	"fmt"
	_ "fmt"
)

type account struct {
	AccountNum string
	pwd string
	balance float64
}

func NewAccount(acnum string) *account {
	return &account{
		AccountNum: acnum,
	}
}

func (account *account) SetPwd(pwd string) {
	if len(pwd)<6 || len(pwd)>10{
		fmt.Printf("wrong pwd")
	}
	(*account).pwd = pwd
}

func (account *account) SetBalance (money float64)   {
	if money <=20{
		fmt.Printf("wrong money")
	}
	(*account).balance += money
}

func (account *account) GetBalance(pwd string) float64  {
	if pwd != (*account).pwd{
		fmt.Printf("wrong pwd")
	}
	return (*account).balance
}

在这里插入图片描述

2、继承

1.引言:
看个学生的考试系统程序,提出代码复用的问题,解决冗余代码,当多个结构体有相同的属性时,可以使用继承
2.关系示意图
在这里插入图片描述
3.在Golang中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和结构体,从而实现了继承特性
(1)使用举例

type Goods struct{
	Name string 
	Price string
}

type Book struct{
	Goods  //匿名结构体
	Writer string
}

(2)案例说明

package main

import (
	"fmt"
	_ "fmt"
)

type Student struct {
	Name string
	Age int
	Score float64
}


//显示他的成绩
func (s *Student) ShowInfo(){
	fmt.Printf("学生名字:%v,年龄%v,成绩%v\n",s.Name,s.Age,s.Score)
}


//显示他的成绩
func (s *Student) SetScore(score float64)  {
	s.Score = score
}

//显示他的状态
func (s *Student) testing()  {
	fmt.Print("testing\n")
}


type Pupil struct {
	Student
}

type Graduate struct {
	Student
}

func main()  {
	//使用方法一
	//小学生
	pupil := &Pupil{}
	pupil.Student.Name = "tom"
	pupil.Student.Age = 8
	pupil.Student.testing()
	pupil.Student.SetScore(70)
	pupil.Student.ShowInfo()
	//大学生
	graduate := &Graduate{}
	graduate.Student.Name = "mary"
	graduate.Student.Age = 8
	graduate.Student.testing()
	graduate.Student.SetScore(70)
	graduate.Student.ShowInfo()
}

4.继承的细节
(1)结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段,方法都可以用
(2)匿名结构体字段访问可以简化:
如:

func main()  {
	//使用方法一
	//小学生
	pupil := &Pupil{}
	pupil.Student.Name = "tom"
	pupil.Student.Age = 8
	pupil.Student.testing()
	pupil.Student.SetScore(70)
	pupil.Student.ShowInfo()
}

可以变成:

func main()  {
	//使用方法一
	//小学生
	pupil := &Pupil{}
	pupil.Name = "tom"
	pupil.Age = 8
	pupil.testing()
	pupil.SetScore(70)
	pupil.ShowInfo()
}

因为编译器会先看pupil有没有这个方法,如果有则直接调用,如果没有就看student里面有没有,有则调用,没有就看是否还有嵌入结构体就再继续找,找到了就调用,最后还没有就报错
(3)当结构体和匿名结构体有相同的字段或者方法时,编译器就采用就近访问原则,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分
(4)结构体嵌入两个(或者多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须指定匿名结构体名字,否则编译报错
(5)如果一个struct结构体嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问结构体的字段或者方法时,就必须带上结构体的名字

type A struct{
	Name string
	Age int
}
type C struct{
	a A
}
func main(){
	var c C
	c.A.Name = "tom" //像这样使用
}

5.多重继承
如一个struct嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现多重继承(不建议使用
6.综合案例

package main

import (
	"fmt"
	_"fmt"
)

type Goods struct {
	Name string
	Price float64
}

type Brand struct {
	Name string
	Address string
}

type TV struct {
	Goods
	Brand
}

type TV2 struct {
	*Goods
	*Brand
}


func main()  {
	tv1 := TV{
		Goods: Goods{"电视机",7000},
		Brand: Brand{"海尔","山东"},
	}
	fmt.Print(tv1)

	tv2 := TV{ Goods{"电视机",8000},Brand{"长虹","北京"}}
	fmt.Print("\n")
	fmt.Print(tv2)

	tv3 :=TV2{
		Goods: &Goods{
			Name:  "电视",
			Price: 6000,
		},
		Brand: &Brand{
			Name:    "创维",
			Address: "河南",
		},
	}
	fmt.Print("\n",tv3)
	fmt.Print("\n",tv3.Goods,tv3.Brand)
	fmt.Print("\n",*tv3.Goods,*tv3.Brand)
}

在这里插入图片描述
5.接口和继承的关系
Tips:
如果这里并没有学过接口的同学,可以先看看下一章关于接口的讲解再回来看接口与继承的关系 Chapter013 golang接口
(1)代码案例

package main

import (
	"fmt"
	_ "fmt"
)

type Monkey struct {
	Name string
}

func (this *Monkey) climbing() {
	fmt.Print(this.Name,"生来会爬树..\n")
}

type LittleMonkey struct {
	Monkey
}

type BirdAble interface {
	Flying()
}

func (this *LittleMonkey) Flying()  {
	fmt.Print(this.Name,"通过学习,会飞翔..\n")
}

type FishAble interface {
	Swimming()
}

func (this *LittleMonkey) Swimming() {
	fmt.Print(this.Name,"通过学习,会游泳..\n")
}


func main()  {
	monkey := LittleMonkey{Monkey{
		Name:"悟空",
	},}
	monkey.climbing()
	//小猴子继承猴子特性
	//对小猴子特殊地拓展————》接口(对继承的补充)
	monkey.Flying()
	monkey.Swimming()
}

在这里插入图片描述
(2)关系
①接口可以在不破坏继承关系的前提下拓展功能,即:实现接口是对继承机制的补充
②接口和继承解决的问题不同
1)继承的价值主要在于:解决代码的 复用性和可维护性
2)接口的价值主要在于:设计,设计好各种规范(方法),让其他自定义类型去实现这些方法
③接口比继承更加灵活
接口比继承更加灵活,继承是满足 is - a的关系,而接口只需要满足like -a的关系
④接口在一定程度上实现 代码解耦

3、多态

1.说明
变量(实例)具有多种形态。面向对象第三大特征,在Go语言中,多态是通过接口来实现的。可以按照统一接口来调用不同的实现。这时接口变量就呈现了不同的形态
2.案例入门
在接口一章中(Chapter013 golang接口),我们使用到了Usb usb ,既可以接受手机变量,又可以接受相机变量,就体现了Usb接口 多态特性。
3.接口体现多态特征
(1)多态参数 :在前面的Usb接口案例,Usb usb,既可以接受手机变量,又可以接受相机变量,就体现了 Usb接口 多态
(2)多态数组:
案例:(断言时细讲)Usb数组中,存放Phone结构体和Camera结构体变量,Phone还有一个特有的方法Call(),请遍历Usb数组,如果是Phone变量,除了调用Usb接口外,还需要调用Phone特有方法Call

package main

import (
	"fmt"
	_ "fmt"
)

type Usb interface {
	Start()
	Stop()
}

type Phone struct {
	Name string
}

func (p Phone) Start()  {
	fmt.Printf("手机开始工作\n")
}

func (p Phone) Stop()  {
	fmt.Printf("手机停止工作\n")
}

type Camera struct {
	Name string
}

func (c Camera) Start()  {
	fmt.Printf("相机开始工作\n")
}

func (c Camera) Stop()  {
	fmt.Printf("相机停止工作\n")
}

type Computer struct {
	Name string
}

func (c Computer) Working(usb Usb)  {
	usb.Start()
	usb.Stop()
}

func main()  {
	//定义一个Usb接口数组,可以存放Phone 和 Camera
	var UsbArr  [3]Usb
	fmt.Print(UsbArr,"\n")
	UsbArr[0] = Phone{"vivo",}
	UsbArr[1] = Phone{"huawei",}
	UsbArr[2] = Camera{"nikang"}
	fmt.Print(UsbArr,"\n")
}

在这里插入图片描述
4.类型断言
(1)案例说明

package main

import (
	"fmt"
	_ "fmt"
)

type Point struct {
	x int
	y int
}

func main()  {
	var a interface{}
	var point Point  = Point{1,2}
	a = point
	//如何将a赋给一个Point变量 ————>断言
	var b Point
	b = a.(Point) //**************************************
	fmt.Print(b)
}

在这里插入图片描述

b = a.(Point)

作用:表示判断a是否是指向Point类型的变量,如果是,就转成Point类型并赋给b变量,否则报错(即:a本来就要指向b)

func main()  {
	//类型断言的其他类型
	var x  interface{}
	var c float32 = 1.1
	x = c
	y:=x.(float32)
	fmt.Printf("y类型是%T",y)
}

如果改成

y:=x.(float64)

报错
在这里插入图片描述
(2)带检查的断言机制
如何在进行断言时,带上检测机制,如果成功就ok,否则就不需要报panic错误

	
	//带检测的类型断言
	var z  interface{}
	var d float32 = 1.1
	z =d
	f,ok :=z.(float64)
	if ok{
		fmt.Print("成功\n")
	}else {
		fmt.Print("失败 继续执行\n")
	}
	fmt.Printf("f类型是%T\n",f)

在这里插入图片描述
(3)类型断言最佳实践
案例1: 给Usb数组中,存放Phone结构体和Camera结构体变量,Phone还有一个特有的方法Call(),请遍历Usb数组,如果是Phone变量,除了调用Usb接口外,还需要调用Phone特有方法Call()

package main

import (
	"fmt"
	_ "fmt"
)

type Usb interface {
	Start()
	Stop()
}

type Phone struct {
	Name string
}

func (p Phone) Start()  {
	fmt.Printf("手机开始工作\n")
}

func (p Phone) Stop()  {
	fmt.Printf("手机停止工作\n")
}

func (p Phone) Call()  {
	fmt.Printf("手机 打电话\n")
}

type Camera struct {
	Name string
}

func (c Camera) Start()  {
	fmt.Printf("相机开始工作\n")
}

func (c Camera) Stop()  {
	fmt.Printf("相机停止工作\n")
}

type Computer struct {
	Name string
}

func (c Computer) Working(usb Usb)  {
	usb.Start()
	//如果是指向Phone结构体变量,那么再来一个Call()方法
	//类型断言
	if phone , ok := usb.(Phone);ok == true{
		phone.Call()
	}
	usb.Stop()
}

func main()  {
	//定义一个Usb接口数组,可以存放Phone 和 Camera
	var UsbArr  [3]Usb
	fmt.Print(UsbArr,"\n")
	UsbArr[0] = Phone{"vivo",}
	UsbArr[1] = Phone{"huawei",}
	UsbArr[2] = Camera{"nikang"}
	fmt.Print(UsbArr,"\n")
	var computer  Computer
	for index, v :=range UsbArr{
		fmt.Print(index)
		computer.Working(v)
	}
}

在这里插入图片描述
案例2: 写一个函数,循环判断传入参数的类型

func TypeJudge(items... interface{}) {
	for index,x :=range items{
		switch x.(type) {
		case bool:
			fmt.Printf("第%v个参数是bool,值是%v\n",index,x)
		case float32:
			fmt.Printf("第%v个参数是float32,值是%v\n",index,x)
		case float64:
			fmt.Printf("第%v个参数是float64,值是%v\n",index,x)
		case int,int32,int64:
			fmt.Printf("第%v个参数是整数,值是%v\n",index,x)
		case string:
			fmt.Printf("第%v个参数是string,值是%v\n",index,x)
		default:
			fmt.Printf("第%v个参数未找到\n",index)
		}
	}
}
func main()  {
	var n1 float32  = 1.1
	var n2 int64  = 3
	var n3 string  = "hello"
	TypeJudge(n1,n2,n3)
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰西啊杰西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值