Go語言無法天然支援繼承,但是又想要實作面向對象的特性。
即父類對象 使用子類對象初始化,那麼該父類對象調用的函數就是子類實作的函數 ,進而滿足LSP(子類交換原則)。
案例一: Go語言 支援擴充父類的功能,如下代碼:
package oriented_test
import (
"fmt"
"testing"
)
// Pet 類
type Pet struct {
}
func (p *Pet) Speak(){ // Pet類的函數成員
fmt.Print("Pet speak.\n")
}
func (p *Pet) SpeakTo(host string) { // Pet類的函數成員
p.Speak()
fmt.Println("Pet SpeakTo ", host)
}
// Dog 擴充Pet的功能
type Dog struct {
p *Pet
}
// 擴充父類的方法
func (d *Dog) Speak(){
d.p.Speak()
}
// 擴充父類的方法
func (d *Dog) SpeakTo(host string) {
d.Speak()
fmt.Println("Dog Speakto ", host)
}
func TestDog(t *testing.T) {
dog := new(Dog)
dog.SpeakTo("Test dog")
}
以上測試代碼的輸出如下:
Pet speak.
Dog Speakto Test dog
dog的SpeakTo中調用了dog 的Speak,其中調用了Pet的Speak,是以輸出正常。
Pet 和 Dog調用不會互相影響,完全由使用者決定。
但是這和我們所想需要的不同,Pet類有自己的方法,Dog類有自己的方法,兩者作用域完全不同。
這裡Go語言推出了匿名嵌套類型,即Dog類不用實作自己的和Pet類同名的方法即可,通過在Dog類的聲明中變更Pet成員。
案例二: Go語言支援匿名函數類型
// Dog 擴充Pet的功能
type Dog struct {
Pet
}
這樣即不需要Dog聲明自己的同名函數成員,預設的調用即為Pet成員函數的調用
package oriented_test
import (
"fmt"
"testing"
)
type Pet struct {
}
func (p *Pet) Speak(){
fmt.Print("Pet speak.\n")
}
func (p *Pet) SpeakTo(host string) {
p.Speak()
fmt.Println("Pet SpeakTo ", host)
}
// Dog 擴充Pet的功能
type Dog struct {
Pet // 支援匿名嵌套類型,
}
func TestDog(t *testing.T) {
var dog Dog
dog.Speak()
dog.SpeakTo("Test dog")
}
最終的輸出如下:
=== RUN TestDog
Pet speak.
Pet speak.
Pet SpeakTo Test dog
--- PASS: TestDog (0.00s)
調用的都是Pet的成員函數,感覺像是繼承了,因為繼承預設就是子類能夠使用父類的公有成員。
在匿名嵌套類型下,我們想要完整嘗試一下Go語言是否真正支援繼承,可以像之前的代碼一樣在Dog中實作Pet的同名函數,且能夠通過父類對象調用子類的成員方法,像C++/Java這樣進行向上類型轉換(本身是不可能的,Go語言不支援顯式類型轉換)。
案例三: Go語言不支援繼承,如下代碼:
package oriented_test
import (
"fmt"
"testing"
)
type Pet struct {
}
func (p *Pet) Speak(){
fmt.Print("Pet speak.\n")
}
func (p *Pet) SpeakTo(host string) {
p.Speak()
fmt.Println("Pet SpeakTo ", host)
}
// Dog 擴充Pet的功能
type Dog struct {
//p *Pet
Pet // 支援匿名嵌套類型
}
// 重載父類的方法
func (d *Dog) Speak(){
fmt.Print("Dog speak.\n")
}
// 重載父類的方法
func (d *Dog) SpeakTo(host string) {
d.Speak()
fmt.Println("Dog Speakto ", host)
}
func TestDog(t *testing.T) {
var dog Pet = new(Dog)
dog.Speak()
dog.SpeakTo("Test dog")
}
在最後的輸出會編譯出錯,不支援将Pet類型轉換為Dog類型:
./oriented_test.go:38:6: cannot use new(Dog) (type *Dog) as type Pet in assignment