本文個人部落格位址:http://www.huweihuang.com/article/golang/golang-object-oriented-programming/
- 面向對象程式設計:
把一組資料結構和處理它們的方法組成對象(object),把相同行為的對象歸納為類(class),通過類的封裝(encapsulation)隐藏内部細節,通過繼承(inheritance)實作類的特化(specialization)[方法的重寫,子類不同于父類的特性]/泛化(generalization)[共性,子類都擁有父類的特性],通過多态(polymorphism)實作基于對象類型的動态分派(dynamic dispatch)。
- 面對對象思想:
面向對象思想是對現實世界事物的抽象,系統中一切事物皆為對象;對象是屬性及其操作的封裝體;對象可按其性質劃分為類,對象成為類的執行個體;執行個體關系和繼承關系是對象之間的靜态關系;消息傳遞是對象之間動态聯系的唯一形式,也是計算的唯一形式;方法是消息的序列。
(一)類型系統[類的聲明]
類型系統:
- 一組基本類型構成的“基本類型集合”;
- “基本類型集合”上定義的一系列組合、運算、轉換方法。
類型系統包括基礎類型(byte、int、bool、float等);複合類型(數組、結構體、指針等);可以指向任何對象的類型(Any類型,類似Java的Object類型);值語義和引用語義;面向對象類型;接口。Go大多數類型為值語義,可以給任何類型添加方法(包括内置類型,不包括指針類型)。Any類型是空接口即interface{}。
1.方法
1、為類型添加方法[類方法聲明],方法即為有接收者的函數
func (對象名 對象類型) 函數名(參數清單) (傳回值清單)
可随時為某個對象添加方法即為某個方法添加歸屬對象(receiver),以方法為中心
在Go語言中沒有隐藏的this指針,即顯示傳遞,形參即為this,例如以下的形參為a。
|
2.值語義和引用語義
值類型:b的修改并不會影響a的值
引用類型:b的修改會影響a的值
Go大多類型為值語義,包括基本類型:byte,int,string等;複合類型:數組,結構體(struct),指針等
|
3.結構體
3、結構體[類屬性的聲明]
struct的功能類似Java的class,可實作嵌套組合(類似繼承的功能)
struct實際上就是一種複合類型,隻是對類中的屬性進行定義指派,并沒有對方法進行定義,方法可以随時定義綁定到該類的對象上,更具靈活性。可利用嵌套組合來實作類似繼承的功能避免代碼重複。
|
(二)初始化[執行個體化對象]
資料初始化的内建函數new()與make(),二者都是用來配置設定空間。差別如下:
- new()
- func new(Type) *Type
- 内置函數
配置設定空間。傳遞給new
函數的是一個類型,不是一個值。傳回值是指向這個新配置設定的零值的指針new
- make()
- func make(Type, size IntegerType) Type
- 内建函數
配置設定并且初始化 一個 slice, 或者 map 或者 chan 對象。 并且隻能是這三種對象。 和make
一樣,第一個參數是 類型,不是一個值。 但是new
的傳回值就是這個類型(即使一個引用類型),而不是指針。 具體的傳回值,依賴具體傳入的類型。make
|
(三)匿名組合[繼承]
組合,即方法代理,例如A包含B,即A通過消息傳遞的形式代理了B的方法,而不需要重複寫B的方法。
繼承是指這樣一種能力:它可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴充。繼承主要為了代碼複用,繼承也可以擴充已存在的代碼子產品(類)。
嚴格來講,繼承是“a kind of ”,即子類是父類的一種,例如student是person的一種;組合是“a part of”,即父類是子類中的一部分,例如眼睛是頭部的一部分。
|
(四)可見性[封裝]
封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的資料和方法隻讓可信的類或者對象操作,對不可信的進行資訊隐藏。
封裝的本質或目的其實程式對資訊(資料)的控制力。封裝分為兩部分:該隐藏的隐藏,該暴露的暴露。封裝可以隐藏實作細節,使得代碼子產品化。
Go中用大寫字母開頭來表示public,可以包外通路;小寫字母開頭來表示private,隻能包内通路;通路性是包級别非類型級别
如果可通路性是類型一緻的,可以加friend關鍵字表示朋友關系可互相通路彼此的私有成員(屬性和方法)
|
(五)接口[多态]
多态性(polymorphisn)是允許你将父對象設定成為和一個或更多的他的子對象相等的技術,指派之後,父對象就可以根據目前指派給它的子對象的特性以不同的方式運作。
簡而言之,就是允許将子類類型的指針指派給父類類型的指針。
即一個引用變量倒底會指向哪個類的執行個體對象,該引用變量發出的方法調用到底是哪個類中實作的方法,必須在由程式運作期間才能決定。不修改程式代碼就可以改變程式運作時所綁定的具體代碼,讓程式可以選擇多個運作狀态,這就是多态性。多态分為編譯時多态(靜态多态)和運作時多态(動态多态),編譯時多态一般通過方法重載實作,運作時多态一般通過方法重寫實作。
5.1接口概念
接口即一組方法的集合,定義了對象的一組行為,方法包含實際的代碼。換句話說,一個接口就是定義(規範或限制),而方法就是實作,接口的作用應該是将定義與實作分離,降低耦合度。習慣用“er”結尾來命名,例如“Reader”。接口與對象的關系是多對多,即一個對象可以實作多個接口,一個接口也可以被多個對象實作。
接口是Go語言整個類型系統的基石,其他語言的接口是不同元件之間的契約的存在,對契約的實作是強制性的,必須顯式聲明實作了該接口,這類接口稱之為“侵入式接口”。而Go語言的接口是隐式存在,隻要實作了該接口的所有函數則代表已經實作了該接口,并不需要顯式的接口聲明。
- 接口的比喻
你的電腦上隻有一個USB接口。這個USB接口可以接MP3,數位相機,攝像頭,滑鼠,鍵盤等。。。所有的上述硬體都可以公用這個接口,有很好的擴充性,該USB接口定義了一種規範,隻要實作了該規範,就可以将不同的裝置接入電腦,而裝置的改變并不會對電腦本身有什麼影響(低耦合)。
- 面向接口程式設計
接口表示調用者和設計者的一種約定,在多人合作開發同一個項目時,事先定義好互相調用的接口可以大大提高開發的效率。接口是用類來實作的,實作接口的類必須嚴格按照接口的聲明來實作接口提供的所有功能。有了接口,就可以在不影響現有接口聲明的情況下,修改接口的内部實作,進而使相容性問題最小化。
當其他設計者調用了接口後,就不能再随意更改接口的定義,否則項目開發者事先的約定就失去了意義。但是可以在類中修改相應的代碼,完成需要改動的内容。
5.2非侵入式接口
非侵入式接口:一個類隻需要實作了接口要求的所有函數就表示實作了該接口,并不需要顯式聲明
|
5.3接口指派
隻要類實作了該接口的所有方法,即可将該類指派給這個接口,接口主要用于多态化方法。即對接口定義的方法,不同的實作方式。
接口指派:
1)将對象執行個體指派給接口
|
2)将接口指派給另一個接口
- 隻要兩個接口擁有相同的方法清單(與次序無關),即是兩個相同的接口,可以互相指派
- 接口指派隻需要接口A的方法清單是接口B的子集(即假設接口A中定義的所有方法,都在接口B中有定義),那麼B接口的執行個體可以指派給A的對象。反之不成立,即子接口B包含了父接口A,是以可以将子接口的執行個體指派給父接口。
- 即子接口執行個體實作了子接口的所有方法,而父接口的方法清單是子接口的子集,則子接口執行個體自然實作了父接口的所有方法,是以可以将子接口執行個體指派給父接口。
|
5.4接口查詢
若要在 switch 外判斷一個接口類型是否實作了某個接口,可以使用“逗号 ok ”。
value, ok := Interfacevariable.(implementType)
其中 Interfacevariable 是接口變量(接口值),implementType 為實作此接口的類型,value 傳回接口變量實際類型變量的值,如果該類型實作了此接口傳回 true。
|
5.5接口類型查詢
在 Go 中,要判斷傳遞給接口值的變量類型,可以在使用 type switch 得到。(type)隻能在 switch 中使用。
|
5.6接口組合
|
5.7Any類型[空接口]
每種類型都能比對到空接口:interface{}。空接口類型對方法沒有任何限制(因為沒有方法),它能包含任意類型,也可以實作到其他接口類型的轉換。如果傳遞給該接口的類型變量實作了轉換後的接口則可以正常運作,否則出現運作時錯誤。
|
5.8接口的代碼示例
|