Go语言没有对象的概念,也没有产生对象的关键字,但是Go语言的特性可以使用原生语法来模拟面向对象的特性。
面向对象的特点是:继承,连接类的层次模型;封装,围绕流程和数据,只能通过定义的 API 访问数据;多态性,即父类中定义的属性或方法被子类修改。继承后,可以具有不同的数据类型或表现出不同的行为。
抽象
面向对象抽象就是将现实世界中的某一类事物抽取出来,并用程序代码来表达。抽象出来的东西一般称为类或接口。
/** 动物类 */
type Animals struct {
name string //动物名称
eat string //动物食性
}
/** 动物接口 */
type AnimalsAbstractMethod interface{
showColor() string //动物颜色
showteech() string //动物牙齿
showlocation() string //生活地区
}
在Go语言中,结构体是属性的集合,并且结构体只能有属性。接口是方法的集合,接口只能是抽象方法(没有方法体)。
继承
子类继承父类的属性和行为,并根据自己的需要扩展行为。
Go语言没有类的概念,也没有extend的用法。要模拟类的行为,您必须具有类的方法和属性。在Go中,结构体可以定义属性,方法可以指向结构体,接口可以定义抽象方法,因此也可以实现继承。
阶级行为
Go中的继承是结构体的嵌套,方法可以直接重写方法体。
//继承模拟
/* 结构体构造属性 */
type Animals struct {
name string //动物名称
eat string //动物食性
}
/* 方法构造类方法 */
func (animals Animals) toString() string {
return "Animals{" + animals.name + "," + animals.eat + "}"
}
/* 结构体嵌套模拟继承 */
type Herbivore struct {
animals Animals //父类嵌套在类中提供父类的属性
teech string
}
/* 重写方法 */
func (berbivore Herbivore) toString() string {
return "Herbivore{name=" + berbivore.animals.name + ",eat=" + berbivore.animals.eat + "}"
}
/* 实例化 */
h1 := Herbivore{
animals: Animals{
"狗子",
"杂食动物",
},
teech: "尖锐的牙齿",
}
fmt.Println(h1)
fmt.Println(h1.toString())
界面行为
Go 中的接口是抽象函数的集合。 Go中的prior class概念与其他语言不同,是一个新概念。使用方法重写接口的抽象方法并将其指向继承的类。
/* 动物接口 */
type animalsBehavior interface {
showColor() string //动物颜色
showlocation() string //生活地区
}
/* 实现接口的方法并指向结构体 */
func (berbivore Herbivore) showColor() {
fmt.Println("打印动物颜色")
}
func (berbivore Herbivore) showlocation() {
fmt.Println("打印动物生活区域")
}
如果重写的方法指向一个结构体,则该结构体的实例可以使用重写的抽象方法。
h1 := Herbivore{
animals: Animals{
"狗子",
"杂食动物",
},
teech: "尖锐的牙齿",
}
fmt.Println(h1)
fmt.Println(h1.toString())
//使用抽象方法
h1.showColor()
h1.showlocation()
封装
封装是面向对象的特性之一,也是对象和类概念的主要特性。封装就是将流程和数据包围起来,只能通过定义好的API来访问数据。
函数是 Go 语言的基本单元。在Go语言中,访问权限是通过变量首字母的大小写来控制的。因此,使用Go来实现面向对象的功能就需要借助这个特性。
Go语言的访问权限控制不像Java那么严格。首字母大写仅限制包外的访问权限,包内可以访问。
定义四个目录如下:
Animals是父类,Herbivore是子类,main是主类,Test是测试类。
- 动物报告go文件的内容
package Animals
/** 动物类 */
type Animals struct {
Name string //动物名称
Eat string //动物食性
}
//方法指向动物结构体
func (animals Animals) makeAnimals(name string, eat string) {
animals.Name = name
animals.Eat = eat
}
func (animals Animals) toString() string {
return "Animals{" + animals.Name + "," + animals.Eat + "}"
}
Animals 结构属性的首字母大写,以便可以在其他目录中访问。编写了两个方法来指向该结构。方法名的第一个字母是小写的,这意味着外部包无法访问它。
将包引入到主类中并调用
package main
import (
"fmt"
"unit4/src/class/Animals"
// "unit4/src/class/Herbivore"
)
func main() {
var a1 = Animals.Animals{
Name: "小狗",
Eat: "杂食动物",
}
fmt.Println(a1)
}
没有小写字母的方法,因此在外部包不能调用。
将成员包改为大写时,如下所示:
//方法指向动物结构体
func (animals Animals) MakeAnimals(name string, eat string) {
animals.Name = name
animals.Eat = eat
}
func (animals Animals) ToString() string {
return "Animals{" + animals.Name + "," + animals.Eat + "}"
}
然后你可以调用该方法,
结构方法和属性的隐私限制是通过首字母大写来完成的。
多态
父类中定义的属性或方法被子类继承后,它们可以具有不同的数据类型或表现出不同的行为。
在上面的例子中,编写一个 Animals 包并定义一个包含以下内容的接口:
type Animals struct {
Name string //动物名称
Eat string //动物食性
}
type animalsBehavior interface {
ShowColor() string
ShowHeight() float32
}
func (animals Animals) ShowColor() {
fmt.Println("animals color")
}
func (animals Animals) ShowHeight() {
fmt.Println("animals height")
}
在其继承的类中,重写父类的方法
type Herbivore struct {
Animals Animals.Animals
Location string
}
/* 重写父类方法 */
func (animals Herbivore) ShowColor() {
fmt.Println("颜色时黄色")
}
func (animals Herbivore) ShowHeight() {
fmt.Println("体重30公斤")
}
生成实例并调用主类中的方法,
h1 := Herbivore.Herbivore{
Animals: Animals.Animals{
Name: "小狗",
Eat: "杂食动物",
},
Location: "主人家",
}
fmt.Println(h1)
h1.ShowColor()
h1.ShowHeight()
h2 := Herbivore.Herbivore{
Animals: Animals.Animals{
Name: "小2",
Eat: "杂食动物2",
},
Location: "主人家2",
}
fmt.Println(h2)
h2.ShowColor()
h2.ShowHeight()
对象的不同实例可以通过不同的实例化和方法重写表现出不同的行为。