object oriented programming
golang 本身並不是純的 OOP,在官網也有寫道 Is Go an object-oriented language?
但可以透過 golang 的 struct
& method
表現的跟其他語言的 class 類似
Structs Instead of Classes
這裡的 employee.go
就像是 class 一樣,在 main.go
裡面可以使用
1
2
3
4
oop
├── employee
│ └── employee . go
└── main . go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// employee.go
package employee
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
TotalLeaves int
LeavesTaken int
}
func ( e Employee ) LeavesRemaining () {
fmt . Printf ( "%s %s has %d leaves remaining" , e . FirstName , e . LastName , ( e . TotalLeaves - e . LeavesTaken ))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// main.go
package main
import "oop/employee"
func main () {
e := employee . Employee {
FirstName : "Sam" ,
LastName : "Adolf" ,
TotalLeaves : 30 ,
LeavesTaken : 20 ,
}
e . LeavesRemaining ()
}
New() function instead of constructors
如果上面改成以下,並不會報錯,會顯示 has 0 leaves remaining
但是這並不是正確的,因為人名都不見了
1
2
3
4
5
6
7
8
9
// main.go
package main
import "oop/employee"
func main () {
var e employee . Employee
e . LeavesRemaining ()
}
為了防止這樣,因此我們可以透過 func
建立類似 建構子 constructors
的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// employee.go
package employee
import (
"fmt"
)
// 改成小寫,因為只需要內部使用
type employee struct {
firstName string
lastName string
totalLeaves int
leavesTaken int
}
// 大寫,讓外部要呼叫只能透過 New()
func New ( firstName string , lastName string , totalLeave int , leavesTaken int ) employee {
e := employee { firstName , lastName , totalLeave , leavesTaken }
return e
}
func ( e employee ) LeavesRemaining () {
fmt . Printf ( "%s %s has %d leaves remaining" , e . firstName , e . lastName , ( e . totalLeaves - e . leavesTaken ))
}
1
2
3
4
5
6
7
8
9
// main.go
package main
import "oop/employee"
func main () {
e := employee . New ( "Sam" , "Adolf" , 30 , 20 )
e . LeavesRemaining ()
}
Composition
go 並不支援繼承(Inheritance),但支援組合(Composition),透過 embedding structs
來達成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main
import (
"fmt"
)
type author struct {
firstName string
lastName string
bio string
}
func ( a author ) fullName () string {
return fmt . Sprintf ( "%s %s" , a . firstName , a . lastName )
}
type post struct {
title string
content string
author
}
func ( p post ) details () {
fmt . Println ( "Title: " , p . title )
fmt . Println ( "Content: " , p . content )
fmt . Println ( "Author: " , p . author . fullName ())
// 這裡就是透過 embedding structs,也可以改寫成 p.fullName(),因為 fullName 並沒有跟 post 裡的 method 衝突到
fmt . Println ( "Bio: " , p . author . bio )
}
func main () {
author1 := author {
"Naveen" ,
"Ramanathan" ,
"Golang Enthusiast" ,
}
post1 := post {
"Inheritance in Go" ,
"Go supports composition instead of inheritance" ,
author1 ,
}
post1 . details ()
}
Embedding slice of structs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main
import (
"fmt"
)
type author struct {
firstName string
lastName string
bio string
}
func ( a author ) fullName () string {
return fmt . Sprintf ( "%s %s" , a . firstName , a . lastName )
}
type post struct {
title string
content string
author
}
func ( p post ) details () {
fmt . Println ( "Title: " , p . title )
fmt . Println ( "Content: " , p . content )
fmt . Println ( "Author: " , p . fullName ())
fmt . Println ( "Bio: " , p . bio )
}
type website struct {
posts [] post
}
func ( w website ) contents () {
fmt . Println ( "Contents of Website" )
for _ , v := range w . posts {
v . details ()
fmt . Println ()
}
}
func main () {
author1 := author {
"Naveen" ,
"Ramanathan" ,
"Golang Enthusiast" ,
}
post1 := post {
"Inheritance in Go" ,
"Go supports composition instead of inheritance" ,
author1 ,
}
post2 := post {
"Struct instead of Classes in Go" ,
"Go does not support classes but methods can be added to structs" ,
author1 ,
}
post3 := post {
"Concurrency" ,
"Go is a concurrent language and not a parallel one" ,
author1 ,
}
w := website {
posts : [] post { post1 , post2 , post3 },
}
w . contents ()
}
Polymorphism
go 要達成多態,必須透過 interface 來實現,只要有 type 實作了 interface 的 function,就可以說這個 type 實作了這個 interface,因此透過這個特性,就能達成 Polymorphism
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main
import (
"fmt"
)
type Income interface {
calculate () int
source () string
}
type FixedBilling struct {
projectName string
biddedAmount int
}
type TimeAndMaterial struct {
projectName string
noOfHours int
hourlyRate int
}
// FixedBilling 實作 interface 的 calculate() & source()
func ( fb FixedBilling ) calculate () int {
return fb . biddedAmount
}
func ( fb FixedBilling ) source () string {
return fb . projectName
}
// TimeAndMaterial 實作 interface 的 calculate() & source()
func ( tm TimeAndMaterial ) calculate () int {
return tm . noOfHours * tm . hourlyRate
}
func ( tm TimeAndMaterial ) source () string {
return tm . projectName
}
// ic 只接收實作了 Income interface 的 type,達成 Polymorphism
func calculateNetIncome ( ic [] Income ) {
var netincome int = 0
for _ , income := range ic {
fmt . Printf ( "Income From %s = $%d\n" , income . source (), income . calculate ())
netincome += income . calculate ()
}
fmt . Printf ( "Net income of organisation = $%d" , netincome )
}
func main () {
project1 := FixedBilling { projectName : "Project 1" , biddedAmount : 5000 }
project2 := FixedBilling { projectName : "Project 2" , biddedAmount : 10000 }
project3 := TimeAndMaterial { projectName : "Project 3" , noOfHours : 160 , hourlyRate : 25 }
incomeStreams := [] Income { project1 , project2 , project3 }
calculateNetIncome ( incomeStreams )
}
參考文件