Go面向对象

特点

  1. 面向对象的三个特性:封装、继承、多态。go 不支持继。
  2. 实例和实例的指针都可以访问封装的数据属性(普通字段)和函数属性(方法)。
  3. struct 对应 python 中的 class
  4. 接口类型是一种抽象的类型,就是在普通类型(出接口类型外的其它类型)的基础上再抽象,然后暴漏出它们共有的方法(顺带也就把它们归类了)

封装

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)
}

猜你喜欢

转载自www.cnblogs.com/wuyongqiang/p/12120446.html