Go语言不是面向对象的语言,只是可以采用面向对象的思维通过一些方法来模拟面向对象。面向对象思维核心就三个点:封装、继承、多态
继承
继承需要符合的关系是is-a,父类更通用,子类更具体
子类会具有父类的一般特性,也会具有自身的特性
继承就是子类继承父类的特征和行为,使得子类具有父类的属性和方法。
Go语言的继承:结构体嵌套
package main
import "fmt"
// 定义一个父类
type Person struct {
name string
age int
}
// 定义一个子类,Student拥有了父类所有的属性,还有自己的特性
type Student struct {
Person // 匿名字段,实现了继承。
school string
}
func main() {
// 1、 创建父类对象
p1 := Person{name: "Autumn", age: 18}
fmt.Println(p1)
fmt.Println(p1.name, p1.age)
// 2、创建子类
s1 := Student{Person: Person{name: "小明", age: 3}, school: "清华"}
fmt.Println(s1)
fmt.Println(s1.Person.name, s1.Person.age, s1.school)
// 3、创建子类
var s2 Student
s2.Person.name = "张三"
s2.Person.age = 3
s2.school = "北大"
fmt.Println(s2)
// 概念:提升字段, 只有匿名字段才可以做到
// Person 在Student中是一个匿名字段, Person中的属性 name age 就是提升字段
// 所有的提升字段就可以直接使用了,不同在通过匿名字段来点了
var s3 Student
s3.name = "李四"
s3.age = 4
s3.school = "清华"
fmt.Println(s3)
fmt.Println(s3.name, s3.age)
}
继承就是子类继承父类的特征和行为,使得子类具有父类的属性和方法,使得子类具有父类相同的行为。子类会具有父类的一般特性也会具有自身的特性。
匿名字段 + 提升字段:Go语言中的匿名字段。
方法
Go语言中同时拥有函数和方法。一定要和其他只有方法的语言区分开
方法:需要指定调用者,约定这个方法属于谁的. 对象.方法()
函数:不需要指定调用者,定义了函数就可以直接函数名()调用
- 方法可以重名,只需要调用者不同
- 如果调用者相同则不可重名
- func (方法调用者)(方法名)(){}
package main
import "fmt"
// 方法:可以理解为函数多了一个调用者
// 方法可以重名,不同的对象,调用的结果是不一样的
type Dog struct {
name string
age int
}
// 方法定义, func 方法调用者 方法名()
// 1、方法可以重名,只需要调用者不同
// 2、如果调用者相同,则不能重名
func (dog Dog) eat() {
fmt.Println("Dog eating...")
}
func (dog Dog) sleep() {
fmt.Println("Dog sleep...")
}
type Cat struct {
name string
age int
}
func (cat Cat) eat() {
fmt.Println("Cat eating...")
}
func (cat Cat) sleep() {
fmt.Println("Cat sleep...")
}
func main() {
// 创建一个对象
dog := Dog{
name: "旺财",
age: 2,
}
fmt.Println(dog)
// 方法的调用,通过对应的结构体对象来调用
dog.eat()
cat := Cat{name: "喵喵", age: 1}
cat.eat()
}
方法:
- 某个类的行为功能,需要指定调用者
- 一段独立的代码功能,必须要使用调用者来调用
- 多个类的方法可以重名,单个类不行
- 方法是某个类的动作
函数:
- 一段独立的代码功能,可以直接调用
- 命名完全不能冲突
- 函数是一个特殊的类型
方法的重写
- 子类可以重写父类的方法
- 子类还可以新增自己的方法
- 子类可以访问父类中的属性和方法
package main
import (
"fmt"
)
// 方法重写,建立在父类和子类结构上的
type Animal struct {
name string
age int
}
func (animal Animal) eat() {
fmt.Println(animal.name, " 正在eating...")
}
func (animal Animal) sleep() {
fmt.Println(animal.name, " 正在sleeping....")
}
// 子类
type Dog struct {
Animal
}
// 子类自己的方法
func (dog Dog) wang() {
fmt.Println("wangwangwanwg~~~")
}
type Cat struct {
Animal
color string // 子类可以定义自己的属性
}
// 子类重写父类的方法 , 子类的方法名和父类同名,即可重写父类的方法
func (cat Cat) eat() {
fmt.Println(cat.name, " 正在吃cat....")
}
func main() {
// 定义一个子类,使用父类方法
dog := Dog{Animal{name: "旺财", age: 3}}
dog.eat() // 调用父类的方法
dog.wang() // 调用自己扩展的方法
cat := Cat{Animal{name: "煤球", age: 3}, "黑色"}
cat.eat() // 如果重写了父类的方法就是调用子类自己的方法
fmt.Println(cat.color) // 调用子类自己的属性
// 子类可以操作父类的方法,父类可以操作子类的吗?不可以
// 父类不能调用子类自己的扩展的方法
a := Animal{name: "大黄", age: 3}
a.eat()
a.sleep()
}
接口
- 接口就是把一些共性的方法集合在一起定义
- 如果有实现类将接口定的方法全部实现了,那么就代表实现了这个接口
- 接口是方法的定义集合,不需要实现具体的方法内容
package main
import (
"fmt"
)
// 接口的定义 interface 来定义,方法太多了,要归类,方法的集合
type USB interface { // 接口,方法的集合
input() // 输入方法
output() // 输出方法
}
// 结构体实现了接口的全部方法就代表实现了这个接口,否则不算实现这个接口
func (mouse Mouse) output() {
fmt.Println(mouse.name, "鼠标输出")
}
func (mouse Mouse) input() {
fmt.Println(mouse.name, "鼠标输入")
}
// 接口嗲用测试
func test(u USB) {
u.input()
u.output()
}
func main() {
// 通过传入接口实现类来进行调用
m1 := Mouse{name: "罗技"}
// test 参数 USB 类型,如果一个结构体实现了这个接口所有的方法,那这个结构体就是这个接口类型的
test(m1)
k1 := KeyBoard{name: "雷蛇"}
test(k1)
// 定义高级类型 k1就升级了 KeyBoard --> USB 向上转型
var usb USB
usb = k1
fmt.Println(usb)
// 接口是无法使用实现类的属性的
//fmt.Println(usb.name)
}
空接口
- 不包含任何方法
- 所有的结构体都默认实现了空接口
- 空接口可以存储任何的类型
多态:Go语言中是模拟多态
一个事物有多种形态
package main
import "fmt"
// 定义接口
type Animal interface {
eat()
sleep()
}
type Dog struct {
name string
}
func (dog Dog) eat() {
fmt.Println(dog.name, "--eat")
}
func (dog Dog) sleep() {
fmt.Println(dog.name, "--sleep")
}
// 多态
func main() {
// Dog 两重身份:1、Dog 2、Animal ,多态
dog1 := Dog{name: "旺财"}
dog1.eat()
dog1.sleep()
// Dog 也可以是 Animal
test2(dog1)
// 定义一个类型可以为接口类型的变量
// 实际上所有实现类都可以赋值给这个对象
var animal Animal // 模糊的 -- 具体化,将具体的实现类赋值给他,才有意义
animal = dog1
test2(animal)
}
最后,GO语言和传统的面向对象编程有所区别,并不是纯粹的面向对象语言。比如C++ Java 的面向对象都是基于类的,但是Go没有类,Go是基于struct来实现OOP特性的。Go去掉了传统的OOP语言的方法重载、构造函数、析构函数等,但是Go仍然有着面向对象编程的继承、封装和多态的特性,只是实现方式比较不同。