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)
}
posted @ 2019-12-30 16:38  黄土地上的黑石头  阅读(143)  评论(0编辑  收藏  举报