前言
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
}