1. 程式人生 > >Go語言面組合式向物件程式設計基礎總結

Go語言面組合式向物件程式設計基礎總結

Go語言的面向物件程式設計簡單而乾淨,通過非侵入式介面模型,否定了C/C++ Java C#等傳統面向物件程式語言的複雜度的必要性,我們發現在Go中即使簡單的組合也能達到傳統面嚮物件語言的效果,而且耦合度非常低,按照Go的作者之一也就是C語言的作者之一說的一句話:Go是更好的C語言。 1、Go中任意型別Any即  interface{}型別,也就是空介面,可以賦值為任意型別 2、可以為其他型別 內建型別 不包括指標型別新增相應的方法 但是注意的一點是一定要用別名。。進行包裝 記住想要 為型別 新增新的方法 那麼請把型別定義別名,別名和原來的型別就不一樣了成了新型別   在Go中只能對非本地型別新增方法......也就是int不能新增方法 需要 type Int int 才可以為Int新增方法 package main import(    "fmt" ) type Integer int func (a Integer) Less(b Integer)bool {     return a<b } func main(){    var a Integer=1    r:=a.Less(2)    fmt.Println(r) } /////用法2 組合之指標 package main import(    "fmt" ) type Integer int func (a *Integer) Less(b Integer)bool {     *a-=10     return *a<b } type Int int func (a *Int) LessIne(b Int)bool{     return *a<b } func main(){    var a Integer=1    var aa int=10    a=Integer(aa)    r:=a.Less(2)    fmt.Println(r) } 3、go中不存在this指標,通過語法糖顯式傳遞物件
在Go語言中沒有隱藏的this指標”這句話的含義是:  方法施加的目標(也就是“物件” )顯式傳遞,沒有被隱藏起來;  方法施加的目標(也就是“物件” )不需要非得是指標,也不用非得叫this。  4、用type定以後的別名型別就是新型別了 只有強制轉換才能使用 package main import(    "fmt" ) type Integer int func (a Integer) Less(b Integer)bool {     return a<b } func main(){    var a Integer=1    var aa int=10    a=Integer(aa)  //不強制轉換會編譯出錯的
   r:=a.Less(2)    fmt.Println(r) } 5、Go中的值語義和引用    channel map本質是指標 因為複製他們沒有意義  ........陣列切片 []type 本質上是值型別 interface介面非常重要 值語義和引用語義的差別在於賦值,比如下面的例子: b = a b.Modify() 如果b的修改不會影響a的值,那麼此型別屬於值型別。如果會影響a的值,那麼此型別是引用 型別。 Go語言中的大多數型別都基於值語義,包括:  基本型別,如byte、int、bool、float32、float64和string等;  複合型別,如陣列(array) 、結構體(struct)和指標(pointer)等。 Go語言中型別的值語義表現得非常徹底。我們之所以這麼說,是因為陣列。 如果讀者之前學過C語言,就會知道C語言中的陣列比較特別。通過函式傳遞一個數組的時 候基於引用語義, 但是在結構體中定義陣列變數的時候基於值語義 (表現在為結構體賦值的時候, 該陣列會被完整地複製) 。 Go語言中的陣列和基本型別沒有區別,是很純粹的值型別,例如: var a = [3]int{1, 2, 3} var b = a b[1]++ fmt.Println(a, b) 該程式的執行結果如下: [1 2 3] [1 3 3]。 這表明b=a賦值語句是陣列內容的完整複製。要想表達引用,需要用指標: var a = [3]int{1, 2, 3} var b = &a b[1]++ fmt.Println(a, *b) 該程式的執行結果如下: [1 3 3] [1 3 3] 這表明b=&a賦值語句是陣列內容的引用。變數b的型別不是[3]int,而是*[3]int型別。 Go語言中有4個型別比較特別,看起來像引用型別,如下所示 陣列切片:指向陣列(array)的一個區間。  map:極其常見的資料結構,提供鍵值查詢能力。  channel:執行體(goroutine)間的通訊設施。  介面(interface) :對一組滿足某個契約的型別的抽象。 但是這並不影響我們將Go語言型別看做值語義。下面我們來看看這4個型別。 陣列切片本質上是一個區間,你可以大致將[]T表示為: type slice struct {     first *T     len int     cap int } 因為陣列切片內部是指向陣列的指標,所以可以改變所指向的陣列元素並不奇怪。陣列切片 型別本身的賦值仍然是值語義。 map本質上是一個字典指標,你可以大致將map[K]V表示為: type Map_K_V struct { // ... } type map[K]V struct {     impl *Map_K_V } 基於指標,我們完全可以自定義一個引用型別,如: type IntegerRef struct {    impl *int } channel和map類似,本質上是一個指標。將它們設計為引用型別而不是統一的值型別的原因 是,完整複製一個channel或map並不是常規需求。 同樣,介面具備引用語義,是因為內部維持了兩個指標,示意為: type interface struct {     data *void     itab *Itab } 介面在Go語言中的地位非常重要。關於介面的內部實現細節,在後面的高階話題中我們再 細細剖析。  7、Go語言中的結構體  組合非繼承
Go語言的結構體(struct)和其他語言的類(class)有同等的地位,但Go語言放棄了包括繼 承在內的大量面向物件特性,只保留了組合(composition)這個最基礎的特性。 組合甚至不能算面向物件特性,因為在C語言這樣的程序式程式設計語言中,也有結構體,也有 組合。組合只是形成複合型別的基礎。 上面我們說到,所有的Go語言型別(指標型別除外)都可以有自己的方法。在這個背景下, Go語言的結構體只是很普通的複合型別,平淡無奇。例如,我們要定義一個矩形型別: type Rect struct {     x, y float64     width, height float64 } 然後我們定義成員方法Area()來計算矩形的面積: func (r *Rect) Area() float64 {     return r.width * r.height } 可以看出, Go語言中結構體的使用方式與C語言並沒有明顯不同。  8、Go中的組合精華  建立結構體指標 和為 結構體擴充成員函式的時候.....傳遞 值型別和指標型別的區別 package main import "fmt" type Rect struct{     x,y float64     width,height float64 } ///如果寫成rct Rect 那麼內部的修改不會影響到 外部結構 ///如果寫成rct*Rect那麼內部的修改會影響到外部結構的值 這就是 指標的效果 func (rct *Rect)Area() float64{      rct.width=1000 ///也可以(*rct).width=1000一樣     return rct.width*rct.height } func main(){      rct:=new(Rect) //對於結構體指標,...呼叫方法和值型別一樣直接.唯一的區別是 作為引數傳遞的時候 傳遞的是地址 值可以被修改  //所以進行組合的時候就有兩種選擇     // 可以寫成 var rct*Rect=&Rect{}     //也可以寫成 var rct Rect=Rect{}    //var rct *Rect=new(Rect)   //也可以寫成 var rct Rect=Rect{1,2,3,4}        rct.width=10.0      rct.height=10.0      area:=rct.Area()      fmt.Println(area)      fmt.Println(rct.width) } 9、普通的組合繼承 ...........................以及組合指標繼承 以及覆蓋 和函式 成員名字衝突  //通過值型別繼承 package main import "fmt" //Go中繼承屬於匿名組合 .......可以從物件繼承 也可以從指標匿名繼承... //匿名繼承會去掉包名,,,所以不能同時繼承類名相同的  即使不在同一個包中 type Base struct{       Name string     Age  uint8 } ///為Base結構體組合進去兩個函式 func (pBase*Base) showName(){      fmt.Println("Age",pBase.Name) } func (pBase*Base) showAge(){      fmt.Println("Age",pBase.Age) } //建立Sub結構體 type Sub struct{     //組合Base修改記憶體模型     //匿名組合進Base 對於呼叫者是不知道的     //即使我們覆蓋了 Base的方法 但是我們還是可以通過xxx.Base.xxx()呼叫基類的方法的    //如果是*Base我們需要在呼叫處手動新增new Base 否則執行會出錯的     Base   } func (pSub*Sub) showName(){   fmt.Println("Before Sub ShowName")     pSub.Base.showName()     fmt.Println("After Sub ShowName") } func main(){       obj:=new(Sub)       obj.Name="張三"       obj.Age=15       obj.showName()       obj.showAge() } ///通過指標型別繼承 package main import "fmt" //Go中繼承屬於匿名組合 .......可以從物件繼承 也可以從指標匿名繼承... //匿名繼承會去掉包名,,,所以不能同時繼承類名相同的  即使不在同一個包中 type Base struct{       Name string     Age  uint8 } ///為Base結構體組合進去兩個函式 func (pBase*Base) showName(){      fmt.Println("Age",pBase.Name) } func (pBase*Base) showAge(){      fmt.Println("Age",pBase.Age) } //建立Sub結構體 type Sub struct{     //組合Base修改記憶體模型     //匿名組合進Base 對於呼叫者是不知道的     //即使我們覆蓋了 Base的方法 但是我們還是可以通過xxx.Base.xxx()呼叫基類的方法的     *Base   } func (pSub*Sub) showName(){   fmt.Println("Before Sub ShowName")     pSub.Base.showName()     fmt.Println("After Sub ShowName") } func main(){       obj:=new(Sub)     //由於使用指標繼承所以 我們要設定匿名組合模板的記憶體物件 地址       obj.Base=&Base{}       obj.Name="張三"       obj.Age=15       obj.showName()       obj.showAge() } 10、Go語言的可見性 許可權是包一級的,包外的不能訪問包內的小寫開頭成員......包內無所謂
11、Go的非侵入式介面 和實現      /////Go語言會為每一個成員函式 自動生成對應的函式  比如 func(a *A) 會自動生成 func (a A) ..... ///反過來則不行 因為 func (a A)這時候傳遞的是形參  (&a).xx()改變的是 引數 副本 而不是 外部類 package main import "fmt" ///非侵入式介面 ////介面 和實現完全分析 減少耦合 ///實現方只負責實現  介面方只負責封裝自己的藉口就行...實現方甚至不知道 有這個介面的存在 這就是 Go的 非侵入式介面的特點 type IFly interface{     fly() } type ISay interface{     say() } type Bird struct{ } //由於匿名傳遞進來的是指標型別 所對於介面的賦值必須是 指標 func (pBird*Bird) fly(){    fmt.Println("i am a bird, i can fly()!") } //由於匿名傳遞的不是指標型別是值型別 所以介面賦值 可以不是指標而是值 func (pBird Bird) say(){    fmt.Println("i am a bird, i can say()!") } func main(){      birdObj:=Bird{}      var iFly IFly=&birdObj      iFly.fly()      var iSay ISay=birdObj      iSay.say() } 13、介面之間是可以相互賦值的 實現了相同方法的介面可以相互賦值,如果介面B是A非超集,那麼  A可以賦值為B 物件不可以被賦值為介面 ,繁殖介面可以被賦值為實現了 某些方法的物件 或者包含他方法的 介面物件 package main import "fmt" ///非侵入式介面 ////介面 和實現完全分析 減少耦合 ///實現方只負責實現  介面方只負責封裝自己的藉口就行...實現方甚至不知道 有這個介面的存在 這就是 Go的 非侵入式介面的特點 type IFly interface{     fly() } type ISay interface{     say() } type IFly1 interface{     fly() } type ISay1 interface{     say() } type Bird struct{ } //由於匿名傳遞進來的是指標型別 所對於介面的賦值必須是 指標 func (pBird*Bird) fly(){    fmt.Println("i am a bird, i can fly()!") } //由於匿名傳遞的不是指標型別是值型別 所以介面賦值 可以不是指標而是值 func (pBird Bird) say(){    fmt.Println("i am a bird, i can say()!") } func main(){      birdObj:=Bird{}      var iFly IFly=&birdObj      iFly.fly()      var iSay ISay=birdObj      iSay.say()      ////介面之間的賦值      var iFly1 IFly1=iFly      iFly1.fly() } 14、Go中的值型別非常的徹底  陣列都是值型別 15、關於給型別新增String()方法   相當於 其他語言的toString 用於列印輸出 package main import "fmt" ///非侵入式介面 ////介面 和實現完全分析 減少耦合 ///實現方只負責實現  介面方只負責封裝自己的藉口就行...實現方甚至不知道 有這個介面的存在 這就是 Go的 非侵入式介面的特點 type IFly interface{     fly() } type ISay interface{     say() } type IFly1 interface{     fly() } type ISay1 interface{     say() } type Bird struct{ } //由於匿名傳遞進來的是指標型別 所對於介面的賦值必須是 指標 func (pBird*Bird) fly(){    fmt.Println("i am a bird, i can fly()!") } //由於匿名傳遞的不是指標型別是值型別 所以介面賦值 可以不是指標而是值 func (pBird Bird) say(){    fmt.Println("i am a bird, i can say()!") } func (pBird Bird) String() string{    return "aaaaaaaaaa" } func main(){      birdObj:=Bird{}      var iFly IFly=&birdObj      iFly.fly()      var iSay ISay=birdObj      iSay.say()      ////介面之間的賦值      var iFly1 IFly1=iFly      iFly1.fly()      fmt.Println(birdObj) } 16、介面的組合 就是把多個介面組合到一起......介面中只有函式沒有屬性 type IFly interface{     fly() } type ISay interface{     say() } type IFly1 interface{     fly() } type ISay1 interface{     say() } type ISay_Fly interface{     ISay     IFly } 17、介面查詢 obj,ok=val.(Interface)   返回查詢的介面 並且返回查詢結果  x.(type) 獲取型別 只能在switch中用  x.(OterTypeInterface) 判斷x是否是指定介面型別 返回指定介面物件,和查詢結果 在Go語言中,還可以更加直截了當地詢問介面指向的物件例項的型別,例如: var v1 interface{} = ... switch v := v1.(type) {     case int:    // 現在v的型別是int     case string: // 現在v的型別是string  ... } 就像現實生活中物種多得數不清一樣,語言中的型別也多得數不清,所以型別查詢並不經常 使用。它更多是個補充,需要配合介面查詢使用,例如: type Stringer interface {     String() string } func Println(args ...interface{}) {     for _, arg := range args {           switch v := v1.(type) {             case int:                        // 現在v的型別是int             case string:                     // 現在v的型別是string             default:             if v, ok := arg.(Stringer); ok { // 現在v的型別是Stringer                 val := v.String()                 // ...             } else {                 // ...             }         }     } } 當然,Go語言標準庫的Println()比這個例子要複雜很多,我們這裡只摘取其中的關鍵部 分進行分析。對於內建型別,Println()採用窮舉法,將每個型別轉換為字串進行列印。對 於更一般的情況,首先確定該型別是否實現了String()方法,如果實現了,則用String()方 法將其轉換為字串進行列印。否則,Println()利用反射功能來遍歷物件的所有成員變數進 行列印。 是的,利用反射也可以進行型別查詢,詳情可參閱reflect.TypeOf()方法的相關文件。此 外, 18、 Any型別  對於匿名結構體賦值給任意型別  沒法取出 具體每個匿名結構體的內部屬性 只能前部列印 通過系統預設的String()函式       var any1 interface{}=1      var any2 interface{}="b"      var any3 interface{}=struct{x ,y string}{"hello,world","aaaaa"}      fmt.Println(any1,any2,any3) 由於Go語言中任何物件例項都滿足空介面interface{},所以interface{}看起來像是可 以指向任何物件的Any型別,如下: var v1 interface{} = 1       // 將int型別賦值給interface{} var v2 interface{} = "abc"   // 將string型別賦值給interface{} var v3 interface{} = &v2     // 將*interface{}型別賦值給interface{} var v4 interface{} = struct{ X int }{1} var v5 interface{} = &struct{ X int }{1} 當函式可以接受任意的物件例項時,我們會將其宣告為interface{},最典型的例子是標 準庫fmt中PrintXXX系列的函式,例如: func Printf(fmt string, args ...interface{}) func Println(args ...interface{}) ... 總體來說,interface{}類似於COM中的IUnknown,我們剛開始對其一無所知,但可以通 過介面查詢和型別查詢逐步瞭解它。 由於Go語言中任何物件例項都滿足空介面interface{},所以interface{}看起來像是可 以指向任何物件的Any型別,如下: var v1 interface{} = 1       // 將int型別賦值給interface{} var v2 interface{} = "abc"   // 將string型別賦值給interface{} var v3 interface{} = &v2     // 將*interface{}型別賦值給interface{} var v4 interface{} = struct{ X int }{1} var v5 interface{} = &struct{ X int }{1} 當函式可以接受任意的物件例項時,我們會將其宣告為interface{},最典型的例子是標 準庫fmt中PrintXXX系列的函式,例如: func Printf(fmt string, args ...interface{}) func Println(args ...interface{}) ... 總體來說,interface{}類似於COM中的IUnknown,我們剛開始對其一無所知,但可以通 過介面查詢和型別查詢逐步瞭解它。

相關推薦

Go語言組合式物件程式設計基礎總結

Go語言的面向物件程式設計簡單而乾淨,通過非侵入式介面模型,否定了C/C++ Java C#等傳統面向物件程式語言的複雜度的必要性,我們發現在Go中即使簡單的組合也能達到傳統面嚮物件語言的效果,而且耦合度非常低,按照Go的作者之一也就是C語言的作者之一說的一句話:Go是更好

GO語言使用之面向物件程式設計(9)面向物件程式設計應用

一、面向物件程式設計的步驟 1、宣告(定義)結構體,確定結構體名 2、編寫結構體的欄位 3、 編寫結構體的方法 二、實現案例: 1) 編寫一個Student結構體,包含name、gen

面向物件程式設計基礎總結

一.面向物件程式設計基本特性 1.一切都是物件 2.程式是物件的集合,物件間通過傳送訊息告訴對方要做的事情 3.物件是類的例項 二.物件是服務的提供者 程式本身是向用戶提供服務 因

go 學習筆記之go是不是物件語言是否支援面對物件程式設計?

面向物件程式設計風格深受廣大開發者喜歡,尤其是以 C++, Java 為典型代表的程式語言大行其道,十分流行! 有意思的是這兩中語言幾乎毫無意外都來源於 C 語言,卻不同於 C 的面向過程程式設計,這種面向物件的程式設計風格給開發者帶來了極大的便利性,解放了勞動,鬆耦合,高內聚也成為設計的標準,從而讓我們

面向物件程式設計基礎

面向物件程式設計 面向物件程式設計:Object Oriented Programming,簡稱OOP,是一種程式設計方法。 面向物件面向過程區別 完成自我介紹功能,面向過程完成功能 stu_a = { "name":"A" "age":18, "home

使用JAVA實現面向物件程式設計基礎

第一章 物件和封裝: 構造方法特點: 方法名和類名相同 沒有返回值型別 系統預設提供無參構造方法 自己編寫構造方法後系統不提供預設構造方法 作用: 完成物件的例項化工作 方法過載(OverLoad) 在同一個類中,方法名相同,引數列表不同的方法稱為方法的過載 引數列表不同指引數個數,

面向函式程式設計和麵物件程式設計的區別和使用

簡述面向函式程式設計和麵向物件程式設計的區別? 什麼時候使用面向函式程式設計?什麼時候使用面向物件程式設計? 函數語言程式設計,顧名思義,這種程式設計是以函式思維做為核心,在這種思維的角度去思考問題。 這種程式設計最重要的基礎是λ演算,接受函式當作輸入和輸出。 面向物件程式設計,這種程

面向過程程式設計和麵物件程式設計的區別

面向過程程式設計 面向過程程式設計是一種以過程為中心的程式設計思想,分析出解決問題的步驟,然後用函式把這些步驟一步一步實現。面向過程程式設計,資料和對資料的操作是分離的。 面向物件程式設計 面向物件程式設計是將事物物件化,通過物件通訊來解決問題。面向物件程式設計,資料和對資料的操作

go語言試題:goroutine、waitgroup、mutex

判斷程式的執行結果,並解釋原因 package main import ( "fmt" "sync" ) const N = 20 func main() { wg := sync.WaitGroup{} mu :

JAVA面向物件程式設計基礎

方法: 1、類似函式 public class Demo { int sum() { return 1+1; } public static void main(String[] args) {

面向過程和麵物件程式設計的的思想理解

      之所以寫這邊部落格,是因為昨日和一位電子專業的好友,聊起了這個專業問題,我卻沒有用通俗易懂的例子來解釋它們,雖然已經把C語言過了一遍,Java也學了好一段時間,但是真正去向一個外行人解釋,感覺只可意會不言傳的感覺,為此非常的懊惱。 面向過程:是一種以過程為中

go語言web框架beego建立專案基礎

開啟瀏覽器輸入Git官網網站回車即可開啟Git官網;如果你是Windows使用者開啟,找到首頁右下角顯示器的圖示,裡面有當前最新版本的版本號,釋出日期。點選裡面的“Downloads for Windows”即調整到下載頁面等待下載即可,如果沒有下載點選“click here to download manu

面向介面程式設計和麵物件程式設計的區別

我想,對於各位使用面向物件程式語言的程式設計師來說,“介面”這個名詞一定不陌生,但是不知各位有沒有這樣的疑惑:介面有什麼用途?它和抽象類有什麼區別?能不能用抽象類代替介面呢?而且,作為程式設計師,一定經常聽到“面向介面程式設計”這個短語,那麼它是什麼意思?有什麼思想內涵?

python面向物件程式設計基礎

       演示了 Python 類與物件的程式設計基礎, 包括屬性、方法、繼承、組合、動態建立類。 python 版本: 2.7.5 class SimpleClass(object): ''' a simple demo for python class

python之面向物件程式設計基礎

面向物件程式設計是一種程式設計正規化,在面向物件程式設計中有一個很重要的概念就是類。 什麼是類呢?類是一個抽象的概念,它是一類具有共同特徵的具體物件的抽象描述。比如在一個學校有張三,李四,王五等學生,他們都是具體的一個個物件(也稱作例項),把他們抽象成一個概念

面向過程程式設計思想和麵物件程式設計思想

一、面向過程程式設計思想 百度百科這樣解釋: “面向過程”(Procedure Oriented)是一種以過程為中心的程式設計思想。 面向過程其實是最為實際的一種思考方式,就算是面向物件的方法也是含有面向過程的思想。可以說面向過程是一種基礎的方法。它考慮的

python08-面向物件程式設計基礎

面向物件程式設計(Object Oriented Programming, OOP),物件中包含了資料與對資料進行操作的方法。python中自定義的物件即是類(class),類定義的一個個實體叫做例項(instance)。 1 類與例項 >>&g

python:面向過程和麵物件程式設計思想

一、區別 面向過程:在實現的時候,每個過程都需要一個函式 面向物件: 二、面向物件和類 類的組成:以狗為例 (1)類名:(狗) (2)類的屬性:一組資料(狗的毛色,重量等) (3)類的方法

面向物件程式設計基礎入門(vb.net版)

幾乎在 Visual Basic 中執行的所有操作都與物件關聯。如果您第一次接觸面向物件的程式設計,則下列術語和概念將幫助您入門。 類和物件單詞“類”和“物件”在面向物件的程式設計中使用得非常多,很容易將它們混淆。一般來說,“類”是一些內容的抽象表示形式,而“物件”是類所表示

Python面向物件程式設計基礎學習筆記

類名大寫開頭; 建構函式 class Obj(Object) nouse = "helo" #類變數,例項共享(類似每個例項複製了一份,而不是static成員), 無法在函式中直