天天看點

Golang 面向對象(封裝、繼承、多态)

前言

Go語言并不像Java那樣有類的概念,以及extends這樣的關鍵字,但是可以用其特有的資料結構來實作類似面向對象的特性。主要有結構體實作封裝,組合實作繼承,接口實作多态。

封裝可以隐藏類的實作細節并使代碼具備子產品化,繼承可以擴充已存在的子產品,多态的作用除了複用性外,還可以解決子產品之間高耦合的問題。

文章目錄

    • 前言
    • 一、結構體實作封裝
    • 二、組合實作繼承
    • 三、接口實作多态
        • 接口定義與實作
        • 接口實作多态

一、結構體實作封裝

在Go語言中,我們可以對結構體的字段進行封裝,并通過結構體中的方法來操作内部的字段。如果結構體中字段名的首字母是小寫字母,那麼這樣的字段是私有的,相當于private字段。外部包裹能直接通路,如果是在名的首字母是大寫字母,那麼這樣的字段對外暴露的,相當于public字段。能夠起的方法也是一樣的,如果方法名首字母是大寫字母,那麼這樣的方法對外暴露的。

下面案例展現了封裝特性:

package main

type Person struct {
	name string
	age int
}

func (p *Person) SetName(name string) {
	p.name = name
}

func (p *Person) SetAge(age int) {
	p.age = age
}

func (p *Person) GetName() string{
	return p.name
}

func (p *Person) GetAge() int {
	return p.age
}
           

二、組合實作繼承

面向對象的繼承特性實際上就是一種元件複用的機制。在Java中可以先定一個父類,然後通過繼承特性來實作子類繼承父類的功能。但Go語言中沒有繼承的關鍵字extends,而是采用組合的方式來實作繼承的效果,組合和繼承是有差別的,組合可以了解為has - a 關系,繼承可以了解為is - a的關系。但他們都實作了代碼複用的目的。組合相對于繼承的優點有:

  • 可以利用面向接口程式設計原則的一系列優點,封裝性行耦合性低
  • 相對于繼承的編譯期确定實作,組合的運作态指定實作更加靈活
  • 組合是非侵入式的,繼承是侵入式的

父類Person類:

type Person struct {
	name string
	age int
}

func (p *Person) Eat() {
	fmt.println("Person Eat")
}

func (p *Person) Walk() {
	fmt.Println("Person Walk")
}
           

子類Student繼承Person類:

type Student struct {
	Person //組合Person,注意首字母大寫,否則無法繼承屬性和方法
	school string
}

func (s *Student) study() {
	fmt.Println(s.name, "study") //調用了name,這裡的name就是繼承自person結構體的
}

//重寫方法,會覆寫Person中的walk方法
func (s *Student) Walk() {
	fmt.Println(s.name, "walk")
}
           

三、接口實作多态

接口定義與實作

接口是一種對約定标準進行定義的,如果一個結構體嵌入了接口類型,那麼任何其他類型實作了該接口都可以與之進行組合調用。接口實作最明顯的優點就是實作了類和接口的分離,在切換實作類的時候不用更換接口功能。

在Go語言中定義接口的文法如下:

type 接口名 interface {
	方法
}
           

在Go語言中對接口的實作隻需要某個類型T實作了接口中的方法,就相當于實作了該接口。定義接口并實作的示例如下:

import "fmt"

//定義一個考試接口
type exam interface {
	exam()
}

type Student struct {
	Person //組合Person,注意首字母大寫,否則無法繼承屬性和方法
	school string
}

//實作了exam接口
func (s *Student) exam() {
	fmt.Println(s.name, "exam")
}
           

接口實作多态

在面向對象的語言中,接口的多種不同實作方式即為多态。多态的示例如下:

package main

import "fmt"

//Person接口
type Person interface {
	ToSchool()
}

//學生類
type Student struct {
	work string
}

//學生類實作Person接口
func (this *Student) ToSchool() {
	fmt.Println("Student ", this.work)
}

//老師類
type Teacher struct {
	work string
}

//老師類實作Person接口
func (this *Teacher) ToSchool() {
	fmt.Println("Teacher ", this.work)
}

//工廠模式函數,根據傳入工作不同動态傳回不同類型
func Factory(work string) Person {
	switch work {
	case "study":
		return &Student{work: "study"}
	case "teach":
		return &Teacher{work: "teach"}
	default:
		panic("no such profession")
	}
}

func main() {
	person := Factory("study")
	person.ToSchool() //Student  study

	person = Factory("teach")
	person.ToSchool() //Teacher  teach
}