Go(三)面向对象

 

 

封装数据和行为

数据封装

结构定义

type Employee struct {
    Id string
    Name string
    Age int
}

field后面没有逗号

实例创建及初始化

e := Employee{"0", "Bob", 20}
e1 := Employee{Name: "Mike", Age: 30}
e2 := new(Employee) // 注意这里返回的引用/指针,相当于e := &Employee{}
e2.Id = "2" // 与其他主要编程语言的差异,通过实例的指针访问成员不需要使用->
e2.Age = 22
e2.Name = "Rose"

检验一下类型

    t.Logf("e is %T", e)
    t.Logf("e2 is %T", e2)

=== RUN TestCreateEmployeeObj
--- PASS: TestCreateEmployeeObj (0.00s)
func_test.go:79: e is fun_test.Employee
func_test.go:80: e2 is *fun_test.Employee
PASS

 

 

行为(方法)定义

与其他主要编程语言的差异

两种方式定义行为:

// 第一种定义方式在实例对应方法被调用时,实例成员会进行值复制
func (e Employee) String() string  {
    return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}

// 通常情况下为了避免内存拷贝我们使用第二种定义方式
func (e *Employee) String() string {
    return fmt.Sprintf("ID:%s/Name:%s/Age:%d", e.Id, e.Name, e.Age)
}

 

 

 

接口

定义交互协议

Java

 

 

                                             

 

 

如果把AClient和接口A打包在一起为packageA,Almpl打包为B

那么A和B 是相互依赖的

一般是接口独立在一个package中,解决循环依赖

 

Go

Duck Type式接口实现

 

 没有显示表明实现接口,只是实现了接口的方法WriteHelloWorld()

 

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 = new(GoProgrammer)
    t.Log(p.WriteHelloWorld())
}

=== RUN TestClient
--- PASS: TestClient (0.00s)
func_test.go:117: fmt.println("Hello World")
PASS

 

与其他主要编程语言的差异

1.接口为非入侵性,实现不依赖于接口定义

2.所以接口的定义可以包含在接口使用者包内

 

 

接口变量

 

 自定义类型

1.type IntConvertionFn func(n int) int

2.type MyPoint int

func timeSpent(inner func(op int)int) func(opt int) int  {
    return func(n int) int {
        start := time.Now()
        ret := inner(n)

        fmt.Println("time spent:", time.Since(start).Seconds())
        return ret
    }
}

参数特别长,自定义一个类型

type IntConv func(op int) int 

func timeSpent(inner IntConv) func(opt int) int  {
    return func(n int) int {
        start := time.Now()
        ret := inner(n)

        fmt.Println("time spent:", time.Since(start).Seconds())
        return ret
    }
}

 

 

 

扩展和复用

争议最大的一块

Go不支持继承

Java代码

class Pet {
    public void speak(){
        System.out.print("...");
    }
    public void speakTo(String name){
        this.speak();
        System.out.println(name);
    }
}

class Dog extends Pet{
    @Override
    public void speak(){
        System.out.println("Wang!");
    }
}

public class InheritanceTest{

    private void makePetSpeak(Pet p){
        p.speak();
        System.out.println("\nPet speak.");
    }

    @Test
    public void  testSubClassAccess(){
        Pet aDog = new Dog();
        aDog.speak();
        aDog.speakTo("Chao");
    }
    @Test
    public void testLSP(){
        Dog aDog = new Dog();
        makePetSpeak(aDog);
    }
}

 makePetSpeak()的参数是Pet类型,接收子类Dog类型是可以的,且会调用Dog的speak

 

 在Go中做同样的事情

使用内嵌

没有继承

dog只能再重写个不同的SpeakTo方法

type Pet struct {

}

func (p *Pet)Speak()  {
	fmt.Print("...")
}

func (p *Pet)SpeakTo(host string)  {
	p.Speak()
	fmt.Println(" ", host)
}

type Dog struct {
	p *Pet
}

func (d *Dog)Speak()  {
	fmt.Println("Wang")
}

func (d *Dog)SpeakTo(host string)  {
	d.Speak()
	//d.p.SpeakTo(host)
   fmt.Println(" ", host)
}

func TestDog(t *testing.T){
   dog := new(Dog)
   dog.SpeakTo("chao")

}

  

 

多态

想支持多态,要使用接口

 

 

 

 空接口与断言

1.空接口可以表示任何类型

2.通过断言来将空接口转换为定制类型

v, ok := p.(int) // ok=true 时则为转换成功

func DoSomething(p interface{})  {
    if i, ok := p.(int); ok{
        fmt.Println("Integer", i)
        return
    }
    if s, ok := p.(string); ok{
        fmt.Println("string", s)
        return
    }
    fmt.Println("Unknow Type")
}

func TestEmptyInterfaceAssertion(t *testing.T)  {
    DoSomething(10)
    DoSomething("10")
}

=== RUN TestEmptyInterfaceAssertion
Integer 10
string 10
--- PASS: TestEmptyInterfaceAssertion (0.00s)
PASS

 

用switch可以简化上面代码

func DoSomething(p interface{})  {
    switch v := p.(type) {
    case int:
        fmt.Println("Integer", v)
    case string:
        fmt.Println("String", v)
    default:
        fmt.Println("Unknown Type")
    }
}

func TestEmptyInterfaceAssertion(t *testing.T)  {
    DoSomething(10)
    DoSomething("10")
}

 

 

 

 

 Go接口最佳实践

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2019-11-24 12:05  AI数据  阅读(175)  评论(0编辑  收藏  举报

导航