成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何使用 Go 語言寫出面向對象風格的代碼

運維 數據庫運維
Go語言本身就不是一個面向對象的編程語言,所以Go語言中沒有類的概念,但是他是支持類型的,因此我們可以使用struct類型來提供類似于java中的類的服務,可以定義屬性、方法、還能定義構造器。

[[433767]]

文末本文轉載自微信公眾號「Golang夢工廠」,作者Golang夢工廠。轉載本文請聯系Golang夢工廠公眾號。

前言

!! 哈嘍,大家好,我是asong。在上一篇文章:小白也能看懂的context包詳解:從入門到精通 分析context的源碼時,我們看到了一種編程方法,在結構體里內嵌匿名接口,這種寫法對于大多數初學Go語言的朋友看起來是懵逼的,其實在結構體里內嵌匿名接口、匿名結構體都是在面向對象編程中繼承和重寫的一種實現方式,之前寫過java、python對面向對象編程中的繼承和重寫應該很熟悉,但是轉Go語言后寫出的代碼都是面向過程式的代碼,所以本文就一起來分析一下如何在Go語言中寫出面向對象的代碼。

面向對象程序設計是一種計算機編程架構,英文全稱:Object Oriented Programming,簡稱OOP。OOP的一條基本原則是計算機程序由單個能夠起到子程序作用的單元或對象組合而成,OOP達到了軟件工程的三個主要目標:重用性、靈活性和擴展性。OOP=對象+類+繼承+多態+消息,其中核心概念就是類和對象。

這一段話在網上介紹什么是面向對象編程時經常出現,大多數學習Go語言的朋友應該也都是從C++、python、java轉過來的,所以對面向對象編程的理解應該很深了,所以本文就沒必要介紹概念了,重點來看一下如何使用Go語言來實現面向對象編程的編程風格。

Go語言本身就不是一個面向對象的編程語言,所以Go語言中沒有類的概念,但是他是支持類型的,因此我們可以使用struct類型來提供類似于java中的類的服務,可以定義屬性、方法、還能定義構造器。來看個例子:

  1. type Hero struct { 
  2.  Name string 
  3.  Age uint64 
  4.  
  5. func NewHero() *Hero { 
  6.  return &Hero{ 
  7.   Name"蓋倫"
  8.   Age: 18, 
  9.  } 
  10.  
  11. func (h *Hero) GetName() string { 
  12.  return h.Name 
  13.  
  14. func (h *Hero) GetAge() uint64 { 
  15.  return h.Age 
  16.  
  17.  
  18. func main()  { 
  19.  h := NewHero() 
  20.  print(h.GetName()) 
  21.  print(h.GetAge()) 

這就一個簡單的 "類"的使用,這個類名就是Hero,其中Name、Age就是我們定義的屬性,GetName、GetAge這兩個就是我們定義的類的方法,NewHero就是定義的構造器。因為Go語言的特性問題,構造器只能夠依靠我們手動來實現。

這里方法的實現是依賴于結構體的值接收者、指針接收者的特性來實現的。

封裝

封裝是把一個對象的屬性私有化,同時提供一些可以被外界訪問的屬性和方法,如果不想被外界訪問,我們大可不必提供方法給外界訪問。在Go語言中實現封裝我們可以采用兩種方式:

Go語言支持包級別的封裝,小寫字母開頭的名稱只能在該包內程序中可見,所以我們如果不想暴露一些方法,可以通過這種方式私有包中的內容,這個理解比較簡單,就不舉例子了。

Go語言可以通過 type 關鍵字創建新的類型,所以我們為了不暴露一些屬性和方法,可以采用創建一個新類型的方式,自己手寫構造器的方式實現封裝,舉個例子:

  1. type IdCard string 
  2.  
  3. func NewIdCard(card string) IdCard { 
  4.  return IdCard(card) 
  5.  
  6. func (i IdCard) GetPlaceOfBirth() string { 
  7.  return string(i[:6]) 
  8.  
  9. func (i IdCard) GetBirthDay() string { 
  10.  return string(i[6:14]) 

聲明一個新類型IdCard,本質是一個string類型,NewIdCard用來構造對象,

GetPlaceOfBirth、GetBirthDay就是封裝的方法。

繼承

Go并沒有原生級別的繼承支持,不過我們可以使用組合的方式來實現繼承,通過結構體內嵌類型的方式實現繼承,典型的應用是內嵌匿名結構體類型和內嵌匿名接口類型,這兩種方式還有點細微差別:

  • 內嵌匿名結構體類型:將父結構體嵌入到子結構體中,子結構體擁有父結構體的屬性和方法,但是這種方式不能支持參數多態。
  • 內嵌匿名接口類型:將接口類型嵌入到結構體中,該結構體默認實現了該接口的所有方法,該結構體也可以對這些方法進行重寫,這種方式可以支持參數多態,這里要注意一個點是如果嵌入類型沒有實現所有接口方法,會引起編譯時未被發現的運行錯誤。

內嵌匿名結構體類型實現繼承的例子

  1. type Base struct { 
  2.  Value string 
  3.  
  4. func (b *Base) GetMsg() string { 
  5.  return b.Value 
  6.  
  7.  
  8. type Person struct { 
  9.  Base 
  10.  Name string 
  11.  Age uint64 
  12.  
  13. func (p *Person) GetName() string { 
  14.  return p.Name 
  15.  
  16. func (p *Person) GetAge() uint64 { 
  17.  return p.Age 
  18.  
  19. func check(b *Base)  { 
  20.  b.GetMsg() 
  21.  
  22. func main()  { 
  23.  m := Base{Value: "I Love You"
  24.  p := &Person{ 
  25.   Base: m, 
  26.   Name"asong"
  27.   Age: 18, 
  28.  } 
  29.  fmt.Print(p.GetName(), "  ", p.GetAge(), " and say ",p.GetMsg()) 
  30.  //check(p) 

上面注釋掉的方法就證明了不能進行參數多態。

內嵌匿名接口類型實現繼承的例子

直接拿一個業務場景舉例子,假設現在我們現在要給用戶發一個通知,web、app端發送的通知內容都是一樣的,但是點擊后的動作是不一樣的,所以我們可以進行抽象一個接口OrderChangeNotificationHandler來聲明出三個公共方法:GenerateMessage、GeneratePhotos、generateUrl,所有類都會實現這三個方法,因為web、app端發送的內容是一樣的,所以我們可以抽相出一個父類OrderChangeNotificationHandlerImpl來實現一個默認的方法,然后在寫兩個子類WebOrderChangeNotificationHandler、AppOrderChangeNotificationHandler去繼承父類重寫generateUrl方法即可,后面如果不同端的內容有做修改,直接重寫父類方法就可以了,來看例子:

  1. type Photos struct { 
  2.  width uint64 
  3.  height uint64 
  4.  value string 
  5.  
  6. type OrderChangeNotificationHandler interface { 
  7.  GenerateMessage() string 
  8.  GeneratePhotos() Photos 
  9.  generateUrl() string 
  10.  
  11.  
  12. type OrderChangeNotificationHandlerImpl struct { 
  13.  url string 
  14.  
  15. func NewOrderChangeNotificationHandlerImpl() OrderChangeNotificationHandler { 
  16.  return OrderChangeNotificationHandlerImpl{ 
  17.   url: "https://base.test.com"
  18.  } 
  19.  
  20. func (o OrderChangeNotificationHandlerImpl) GenerateMessage() string { 
  21.  return "OrderChangeNotificationHandlerImpl GenerateMessage" 
  22.  
  23. func (o OrderChangeNotificationHandlerImpl) GeneratePhotos() Photos { 
  24.  return Photos{ 
  25.   width: 1, 
  26.   height: 1, 
  27.   value: "https://www.baidu.com"
  28.  } 
  29.  
  30. func (w OrderChangeNotificationHandlerImpl) generateUrl() string { 
  31.  return w.url 
  32.  
  33. type WebOrderChangeNotificationHandler struct { 
  34.  OrderChangeNotificationHandler 
  35.  url string 
  36.  
  37. func (w WebOrderChangeNotificationHandler) generateUrl() string { 
  38.  return w.url 
  39.  
  40. type AppOrderChangeNotificationHandler struct { 
  41.  OrderChangeNotificationHandler 
  42.  url string 
  43.  
  44. func (a AppOrderChangeNotificationHandler) generateUrl() string { 
  45.  return a.url 
  46.  
  47. func check(handler OrderChangeNotificationHandler)  { 
  48.  fmt.Println(handler.GenerateMessage()) 
  49.  
  50. func main()  { 
  51.  base := NewOrderChangeNotificationHandlerImpl() 
  52.  web := WebOrderChangeNotificationHandler{ 
  53.   OrderChangeNotificationHandler: base, 
  54.   url: "http://web.test.com"
  55.  } 
  56.  fmt.Println(web.GenerateMessage()) 
  57.  fmt.Println(web.generateUrl()) 
  58.  
  59.  check(web) 

因為所有組合都實現了OrderChangeNotificationHandler類型,所以可以處理任何特定類型以及是該特定類型的派生類的通配符。

多態

多態是面向對象編程的本質,多態是支代碼可以根據類型的具體實現采取不同行為的能力,在Go語言中任何用戶定義的類型都可以實現任何接口,所以通過不同實體類型對接口值方法的調用就是多態,舉個例子:

  1. type SendEmail interface { 
  2.  send() 
  3.  
  4. func Send(s SendEmail)  { 
  5.  s.send() 
  6.  
  7. type user struct { 
  8.  name string 
  9.  email string 
  10.  
  11. func (u *user) send()  { 
  12.  fmt.Println(u.name + " email is " + u.email + "already send"
  13.  
  14. type admin struct { 
  15.  name string 
  16.  email string 
  17.  
  18. func (a *admin) send()  { 
  19.  fmt.Println(a.name + " email is " + a.email + "already send"
  20.  
  21. func main()  { 
  22.  u := &user
  23.   name"asong"
  24.   email: "你猜"
  25.  } 
  26.  a := &admin{ 
  27.   name"asong1"
  28.   email: "就不告訴你"
  29.  } 
  30.  Send(u) 
  31.  Send(a) 

總結

歸根結底面向對象編程就是一種編程思想,只不過有些語言在語法特性方面更好的為這種思想提供了支持,寫出面向對象的代碼更容易,但是寫代碼的還是我們自己,并不是我們用了java就一定會寫出更抽象的代碼,在工作中我看到用java寫出面向過程式的代碼不勝其數,所以無論用什么語言,我們都應該思考如何寫好一份代碼,大量的抽象接口幫助我們精簡代碼,代碼是優雅了,但也會面臨著可讀性的問題,什么事都是有兩面性的,寫出好代碼的路還很長,還需要不斷探索............。

文中示例代碼已經上傳github:https://github.com/asong2020/Golang_Dream/tree/master/code_demo/oop

 

責任編輯:武曉燕 來源: Golang夢工廠
相關推薦

2009-08-07 10:20:38

WebSphere A

2024-04-02 07:32:58

Go語言接口

2021-05-28 05:34:06

Golang語言編程

2024-01-08 07:02:48

數據設計模式

2022-11-28 08:15:14

Go語言代碼

2022-12-05 09:32:29

Go 語言風格規范

2013-03-11 09:23:22

Go語言面向對象

2022-10-21 09:01:41

StudentC++類型

2010-03-01 17:47:53

Python語言

2021-05-20 08:54:16

Go面向對象

2021-12-27 08:27:18

RepoGo 代碼

2020-07-15 08:17:16

代碼

2009-07-14 16:51:50

Jython中的對象

2020-05-14 09:15:52

設計模式SOLID 原則JS

2023-12-06 15:40:17

AI

2009-02-13 09:12:34

JavaFX中高端手機Java

2019-11-18 17:05:02

JavaScript面向對象程序編程Java

2010-08-24 16:00:43

C語言

2011-06-02 09:47:11

C語言重構

2023-11-26 19:06:13

GO測試
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲国产精品福利 | 日韩字幕一区 | 国产成人精品综合 | 国产精品一区二区av | 欧美一区2区三区4区公司 | 国产精品乱码一区二三区小蝌蚪 | 羞羞视频在线观免费观看 | 国产精品亚洲综合 | 97精品视频在线 | 久久精片 | 欧美精品一区在线 | 伊人久久伊人 | 成人免费在线网 | a级片在线观看 | 色婷婷综合成人av | 成人精品在线观看 | 久久精品国产亚洲夜色av网站 | 国产成人jvid在线播放 | 久久精品国产清自在天天线 | 在线观看黄色电影 | 亚洲成人免费av | 亚洲一区二区精品视频在线观看 | 欧美专区在线观看 | 欧美精品一区二区三区在线播放 | 日日操日日舔 | 爱爱视频日本 | 黑人巨大精品欧美黑白配亚洲 | av手机在线看 | 国产欧美一区二区三区在线播放 | 精产国产伦理一二三区 | 国产成人精品免高潮在线观看 | 色桃网| www.日韩 | 亚洲一区二区三区久久 | 日韩精品成人网 | 日韩在线电影 | 奇米超碰在线 | 国产一区二区精品在线观看 | 在线永久看片免费的视频 | 视频一区 国产精品 | 欧美精品一区二区三区在线四季 |