Go面向对象
特点
- 面向对象的三个特性:封装、继承、多态。go 不支持继。
- 实例和实例的指针都可以访问封装的数据属性(普通字段)和函数属性(方法)。
- struct 对应 python 中的 class
- 接口类型是一种抽象的类型,就是在普通类型(出接口类型外的其它类型)的基础上再抽象,然后暴漏出它们共有的方法(顺带也就把它们归类了)
封装
package struct_lean
import (
"fmt"
"testing"
"unsafe"
)
type Employee struct {
Id string
Name string
Age int
}
func TestCreateEmployeeObj(t *testing.T) {
e := Employee{"0", "Bob", 15}
e1 := Employee{Name:"Tom", Age:30}
e2 := new(Employee) // 返回指针
e2.Id = "2"
e2.Name = "Jake"
e2.Age = 16
t.Log(e)
t.Log(e1)
t.Log(e2)
t.Log(e2.Age)
}
// 方式一:这种方式在实例对应方法被调用时,实例的成员会进行复制
//func (e Employee) String() string {
// fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
// return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
//}
// 方式二:使用这种方式可以避免内存拷贝
func (e *Employee) String() string {
fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}
func TestStructOperations(t *testing.T) {
e := Employee{"0", "Bob", 20}
fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
t.Log(e.String())
}
运行上面的TestStructOperations,我们可以通过判断打印的两个ID值是否相等来判断是否发生内存拷贝
不支持继承,支持组合
可以实现方法重载,但是不能实现子类替换父类,不能实现真正的继承
package inherit_test
import (
"fmt"
"testing"
)
// Pet 相当于基类
type Pet struct {
}
func (p *Pet) Speak() {
fmt.Print("...")
}
func (p *Pet) SpeakTo(host string) {
p.Speak()
fmt.Print(" ", host)
}
// Dog 相当于子类
type Dog struct {
*Pet
}
// 把父类的方法重写
func (d *Dog) Speak() {
fmt.Print("Wang!")
}
func TestDog(t *testing.T) {
dog := new(Dog)
dog.SpeakTo("MaYun")
}
运行上面测试程序打印"... MaYun"并不是"Wang! MaYun",子类的 Speak 没有执行;
Pet 和 Dog 是完全不同的两种类型,我们没有办法把进行相互转换(实现不了LSP),所以 go 不支持继承。
这其实就是个组合
接口
package interface_test
import "testing"
type Programmer interface {
WriteHelloWorld() string
}
type GoProgrammer struct {
}
func (g *GoProgrammer) WriteHelloWorld() string {
return "fmt.Println(\"Hello World\")"
}
func TestClient(t *testing.T) {
var p Programmer
// p 声明为 Programmer 类型,但是赋值为 *GoProgrammer 也不会 panic, 这就是接口的用途
// p = &GoProgrammer{}
p = new(GoProgrammer) // 必须用指针去调用接口的成员
t.Log(p.WriteHelloWorld())
}
多态
通过接口的方式支持多态
package polym_test
import (
"fmt"
"testing"
)
type Code string
type Programmer interface {
WriteHelloWorld() Code
}
type Goprogrammer struct {
}
func (g *Goprogrammer) WriteHelloWorld() Code {
return "fmt.Println(\"Hello World!\")"
}
type JavaProgrammer struct {
}
func (j JavaProgrammer) WriteHelloWorld() Code {
return "System.out.Println(\"Hello World!\")"
}
func writeFirstProgram(p Programmer) {
fmt.Printf("%T %v\n", p, p.WriteHelloWorld())
}
// 多态测试
func TestPolymorphism(t *testing.T) {
goProg := new(Goprogrammer) // interface 只能对应指针实例
javaProg := new(JavaProgrammer)
writeFirstProgram(goProg)
writeFirstProgram(javaProg)
}