go面向对象

面向对象

封装

封装就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其他包只有通过被授权的操作(方法),才能对字段进行操作。

//封装
//不能随便查看人的工资等隐私,并对输入的年龄进行合理的验证

type person struct {
	Name string
	age  int
	wage float64
}

func NewPerson(name string) *person {
	return &person{
		Name: name,
	}
}
func (p *person) SetAge(age int) {
	if age < 0 || age > 130 {
		fmt.Println("你输入的年龄不合理")
		return
	}
	p.age = age
}
func (p *person) GetAge() int {
	return p.age
}

func (p *person) SetWage(wage float64) {
	if wage < 0 {
		fmt.Println("你输入的薪水不合理")
		return
	}
	p.wage = wage
}
func (p *person) GetWage() float64 {
	return p.wage
}

好处:

  • 隐藏实现细节
  • 提前对对数据验证

如何体现封装:

  • 对结构体中的属性进行封装
  • 使用方法和包实现封装

封装的实现步骤

  1. 将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似 private)
  2. 给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
  3. 提供一个首字母大写的 Set 方法(类似其它语言的 public),用于对属性判断并赋值
    func (var 结构体类型名) SetXxx(参数列表) (返回值列表) {
    //加入数据验证的业务逻辑
    var.字段 = 参数
    }
  4. 提供一个首字母大写的 Get 方法(类似其它语言的 public),用于获取属性的值
    func (var 结构体类型名) GetXxx() {
    return var.age;
    }

特别说明:在 Golang 开发中并没有特别强调封装,这点并不像 Java. 所以提醒学过 java 的朋友,
不用总是用 java 的语法特性来看待 Golang, Golang 本身对面向对象的特性做了简化的.

继承

继承可以解决代码复用,让我们的编程更加靠近人类思维。

当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法。其它的结构体不需要重新定义这些属性(字段)和方法,只需嵌套一个 Student 匿名结构体即可。

import "fmt"

// 继承

type Student struct {
	Name  string
	Age   int
	Score float64
}

type Pupil struct {
	Grade string
	Student
}
type Graduate struct {
	Grade string
	Student
}

// 展示他的成绩
func (s *Student) ShowInfo() string {
	return fmt.Sprintf("name: %s, age: %d, score: %f", s.Name, s.Age, s.Score)
}

func (s *Student) SetScore(score float64) {
	//业务判断
	s.Score = score
}

func (s *Student) testing(Grade string) {
	fmt.Printf("%s正在考试\n", Grade)
}

func main() {
	var p *Pupil = &Pupil{
		Grade: "小学生",
		Student: Student{
			Name: "Tom",
			Age:  10,
		},
	}
	var graduate *Graduate = &Graduate{
		Grade: "大学生",
		Student: Student{
			Name: "Jack",
			Age:  20,
		},
	}
	p.testing(p.Grade)
	p.SetScore(99.0)
	fmt.Println(p.ShowInfo())
	fmt.Println("---------------------")
	graduate.testing(graduate.Grade)
	graduate.SetScore(60.0)
	fmt.Println(graduate.ShowInfo())
}

上面代码中Graduate 和 Pupil 结构体中分别嵌套了Student 这个结构体,继承了Student中的字段和方法。

继承的细节

1.结构体可以使用嵌套匿名结构体所有的字段和方法, 即:首字母大写或者小写的方法,字段都可以使用
2.当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分
3.如果一个 struct 嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,必须带上结构体的名字

type D struct{
	a A //有名结构体
}
var d D
d.a.Name="jack"

多重继承

如一个 struct 嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。

type Goods struct{
	Name string
	Price float64
}
type Brand struct{
	Name string
	Address string
}
type TV struct{
	Goods
	Brand
}
多重继承的细节

1.如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分。

  1. 为了保证代码的简洁性,建议大家尽量不使用多重继承

继承和接口的区别

1.当 A 结构体继承了 B 结构体,那么 A 结构就自动的继承了 B 结构体的字段和方法,并且可以直接使用

  1. 当 A 结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,因此我们可以认为:实现接口是对继承机制的补充. 实现接口可以看作是对继承的一种补充
    3.接口和继承解决的解决的问题不同:
    继承的价值主要在于:解决代码的复用性和可维护性。
    接口的价值主要在于:设计好各种规范(方法),让其它自定义类型去实现这些方法。
    接口比继承更加灵活: 继承是满足 is - a 的关系,而接口只需满足 like - a 的关系。接口在一定程度上实现代码解耦

多态

在Go语言中,多态特征是通过接口实现的,可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。

体现多态的两种形式

多态参数
在下面的 Usb 接口案例,Usb usb ,即可以接收手机变量,又可以接收相机变量,就体现了 Usb 接口多态。

//多态参数
import (
	"fmt"
)

// 声明/定义一个接口
type Usb interface {
	//声明了两个没有实现的方法
	Start()
	Stop()
}

type Phone struct {
}

// 让 Phone 实现 Usb 接口的方法
func (p Phone) Start() {
	fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
	fmt.Println("手机停止工作。。。")
}

type Camera struct {
}

// 让 Camera 实现 Usb 接口的方法
func (c Camera) Start() {
	fmt.Println("相机开始工作。。。")
}
func (c Camera) Stop() {
	fmt.Println("相机停止工作。。。")
}

type Computer struct {
}

// 编写一个方法 Working 方法,接收一个 Usb 接口类型变量
// 只要是实现了 Usb 接口 (所谓实现 Usb 接口,就是指实现了 Usb 接口声明所有方法)
// 这一步其实就实现了多态(usb Usb)就是多态参数
func (c Computer) Working(usb Usb) { //usb 变量会根据传入的实参,来判断到底是 Phone,还是 Camera
	//通过 usb 接口变量来调用 Start 和 Stop 方法
	usb.Start()
	usb.Stop()
}
func main() {
	//测试
	//先创建结构体变量
	computer := Computer{}
	phone := Phone{}
	camera := Camera{}
	//关键点
	computer.Working(phone)
	computer.Working(camera) //
}

多态数组
演示一个案例:给 Usb 数组中,存放 Phone 结构体 和 Camera 结构体变量

//多态数组
import (
	"fmt"
)

// 声明/定义一个接口
type Usb interface {
	//声明了两个没有实现的方法
	Start()
	Stop()
}

type Phone struct {
	name string
}

// 让 Phone 实现 Usb 接口的方法
func (p Phone) Start() {
	fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
	fmt.Println("手机停止工作。。。")
}

type Camera struct {
	name string
}

// 让 Camera 实现 Usb 接口的方法
func (c Camera) Start() {
	fmt.Println("相机开始工作。。。")
}
func (c Camera) Stop() {
	fmt.Println("相机停止工作。。。")
}

func main() {

	//定义一个Usb接口数组,可以存放Phone和Camera的结构体变量
	//这里就体现出多态数组
	var usbArr [3]Usb
	usbArr[0] = Phone{"荣耀"}
	usbArr[1] = Phone{"小米"}
	usbArr[2] = Camera{"索尼"}

	fmt.Println(usbArr)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值