golang学习路径03面向对象封装继承多态

Posted 如何在5年薪百万

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang学习路径03面向对象封装继承多态相关的知识,希望对你有一定的参考价值。

六、面向对象

  1. 仅支持封装,不支持继承和多态
  2. go语言没有class有struct
  3. go没有构造器,可以使用工厂方法代替

通过面向对象学习struct和interface

6.1 type关键字

定义一种新的数据类型

func testType()  

	// type代表定义一种新的类型,这里等同于int类型的别名。
	// 一般用来定义结构体或者接口
	type number int

	var b number =10
	fmt.Println(b)

6.2 struct定义和初始化

结构体可以包含多个类型的组合,接近java中的类对象

定义stuct
type treeNode struct 
	value       int
	left, right *treeNode



	var root treeNode
	//创建对象的方法
	//1 指定单个参数
	root = treeNodevalue: 3
	//2. 使用指针创建
	root.right = &treeNode
	//3. 指定全部参数
	root.left = &treeNode5, nil, nil
	//4. new关键字创建
	root.right.left = new(treeNode)
	//5. 工厂模式创建
	root.left.right = treeNodeFactory(2)

	//6. 数组定义可以简写
	nodes := []treeNode
		value: 3,
		,
		6, nil, nil,
	

方法属性

  1. 比普通func多了一个(接收对象 类型),其他和普通函数没有区别
  2. 通过指针实现值传递
  3. nil指针可以安全使用,调用方法
//给tree定义一个方法print
//小括号代表this指向括号内接收的对象,node指向对象引用
func (node treeNode) print() 
	fmt.Println(node.value)


//set pointer实现引用传递
func (node *treeNode) setValue(val int) 
	node.value = val

值接收 vs 指针接收

  1. 要改变内容必须使用指针接收
  2. 结构过大也是用指针接收
  3. 如果已经使用了指针接收,最好保持一致
package main

import "fmt"

func main()
	p1:=People
		name:   "matthew",
		age:    33,
		gender: false,
	
	p1.showPeople()

	p1.setName("lisi")
	fmt.Println("getName",p1.getName())



func testType()  

	// type代表定义一种新的类型,这里等同于int类型的别名。
	// 一般用来定义结构体或者接口
	type number int

	var b number =10
	fmt.Println(b)


// 定义一个people的结构体
type People struct 
	name string
	age int
	gender bool


//get 方法
func (this *People)getName()  string 
	return this.name


//set 方法,struct是值传递,所以必须使用指针达成引用传递效果
func (this *People)setName(name string)  
	this.name=name


//string 方法
func(this *People)showPeople()
	fmt.Println(this)

struct的方法无论使用值接收,还是指针接收,调用方式无变化

6.3 接口Interface

  1. 接口是万能类型,基础类型如int、struct都实现了interface,所以interface可以接收任何类型。
  2. 接口实现是隐式的,实现接口中的所有方法就代表实现了改接口

duck typing:描述事物外部行为而非内部结构,从使用者角度看待。go属于结构化类型系统,接近duck typing

接口定义

  • 接口定义了一个方法名字,返回值和参数,不需要方法体
  • 接口可以作为参数在函数中传递
  • 貌似不能有属性,只能有方法
//接口定义一个方法类型
type Retriver interface 
	Get(string) string


//函数中使用接口作为参数传递
func download(r Retriver, url string) string 
	return r.Get(url)

接下来定义接口的实现

  1. 只要实现了接口的方法就默认实现了接口
  2. 实现了接口就具备了多态的可能

定义一个type用于mock请求返回一个字符串

package mock

type Retriver struct 
	Content string


// struct实现了接口的方法,也就实现了接口
func (r Retriver) Get(url string) string 
	return r.Content


定义一个类似的接口,真实的获取网页的地址

package real

import (
	"net/http"
	"net/http/httputil"
	"time"
)

type Retriver struct 
	UserAgent string
	Timerout  time.Duration


func (r Retriver) Get(s string) string 
	get, err := http.Get(s)
	if err != nil 
		panic(err)
	

	response, err := httputil.DumpResponse(get, true)
	defer get.Body.Close()
	if err != nil 
		panic(err)
	
	return string(response)


interface万能类型

基础类型int,flat,stuct等都实现了interface,所以后者可以作为万能类型


func printVal(val interface)
	fmt.Println(val)

type Book struct 
	name string


func main()  

	//interface可以作为万能类型
	book:=Bookname: "MyHeart"
	printVal(100)
	printVal("string")
	printVal(3.14)
	printVal(book)

判断接口类型

  1. 通过变量.(类型)判断是否是指定类型,ok代表true
  2. 通过printF %T打印实际类型
func printVal1(val interface)

	value,ok:=val.(string) //类型判断,是否是string类型,ok代表是string
	if ok
		fmt.Println(value)
	else 
		fmt.Printf("val is not string,type is %T \\n",val)
	




func main()  

	fmt.Println("-------")
	//接口类型判断
	printVal1(100)
	printVal1("hello")


  • 表示任何类型: interface
  • 类型判断 type Assertion
  • 类型选择 type Swtich

golang系统接口参考

  • Stringer 格式化输出
  • Reader
  • Writer

6.3 子类继承父类

  1. 在子类定义时,写入父struct名称,即继承了父类
  2. 子类可以添加新的属性和方法
  3. 子类可以直接调用父类的属性和方法
  4. 可见性仅有首字母大小写控制
package main

import "fmt"

/**
子类继承父类
 */

func main()  

	student:=Student
		People: People
			name:"xiaowang",
			age:9,
			gender:true,
		,
		grade:  3,
	

	student.ShowStudent()
	fmt.Println("people name",student.name) //获取父类属性
	fmt.Println("student grade",student.grade) //获取父类属性
	student.Eating() //调用父类方法
	student.study() //调用子类方法


type Student struct 
	People //子类Student继承父类的属性和方法
	grade int //年级


//子类增加新的方法
func (s *Student) study()  
	fmt.Println("student is studying")


func (s *Student)ShowStudent()  
	fmt.Println(s)




// 定义一个people的结构体
type People struct 
	name string
	age int
	gender bool


//get 方法
func (this *People)GetName()  string 
	return this.name


//set 方法,struct是值传递,所以必须使用指针达成引用传递效果
func (this *People)setName(name string)  
	this.name=name


func (this *People) Eating() 
	fmt.Println("People is eating")


//string 方法
func(this *People) ShowPeople()
	fmt.Println(this)


6.4 多态 interface

golang中的多态概念上和java完全一致,需满足三个条件

  1. 定义父类对象,go中必须是interface
  2. 定义子类struct,实现父类全部方法(否则不满足继承条件)
  3. 父类对象(pointer指针变量)指向(引用)子类变量地址

仔细研究下面代码,体会多态的含义

package main

import "fmt"

/**
1. 定义父类接口
 */
type Animal interface 
	GetColor() string
	Eat()
	Sleep()


/**
2.1 定义子类Dog,必须实现所有方法
 */
type Dog struct 
	color string


func (dog *Dog)Eat()  
	fmt.Println("dog is eating")


func (dog *Dog) Sleep()  
	fmt.Println("dog is sleeping")


func (dog *Dog)GetColor() string 
	return "dog "+ dog.color



/**
2.2 定义子类Cat,同上。两者的方法有不同实现
 */

type Cat struct 
	color string

func (cat *Cat)Eat()  
	fmt.Println("cat is eating")


func (cat *Cat)Sleep()  
	fmt.Println("cat is sleeping")


func (cat *Cat)GetColor() string 
	return "cat " + cat.color



//多态传参,根据传入的引用类型调用对应方法
func showColor(animal Animal)
	fmt.Println(animal.GetColor())


func main()
	// 3. 父类指向子类对象

	var animal Animal //父类指针
	animal=&Catcolor: "white"
	animal.Sleep()  //cat is sleeping
	showColor(animal)
	fmt.Println("-----------")
	animal=&Dogcolor: "yellow"
	showColor(animal)
	animal.Eat() //dog is eating



以上是关于golang学习路径03面向对象封装继承多态的主要内容,如果未能解决你的问题,请参考以下文章

[Golang]面向对象营养餐,一文管够(封装,继承,多态)

GoLang中面向对象的三大特性

Go_15:GoLang中面向对象的三大特性

go语言学习面向对象oop

『GoLang』面向对象

PHP面向对象三大特点学习(充分理解抽象封装继承多态)