Encapsulation trong Golang

Post on: 2023-04-17 22:24:58 | in: Golang
Trong Go, Encapsulation được thực hiện bằng cách sử dụng các kỹ thuật giới hạn truy cập (access modifiers) cho các thành phần của một đối tượng.

Golang cung cấp tính đóng gói (encapsulation) ở mức độ gói (package). Go không có bất kỳ từ khóa public, private hoặc protected. Cơ chế duy nhất để kiểm soát tính nhìn thấy của các thành phần là sử dụng định dạng viết hoa và viết thường.

  • Các identifier được viết hoa (capitalized) là được xuất (exported). Chữ cái đầu tiên được viết hoa cho thấy đây là một identifier được xuất.

  • Các identifier viết thường (non-capitalized) không được xuất (non-exported). Chữ cái viết thường cho thấy rằng identifier không được xuất và chỉ có thể truy cập từ trong cùng một package.

Có năm loại identifier có thể được xuất hoặc không xuất:

  • Hàm (function)
  • Kiểu (type)
  • Biến (variable)
  • Hằng số (constant)
  • Trong một số trường hợp, phương thức (method) cũng có thể được xuất hoặc không xuất.

Hãy xem một ví dụ thể hiện việc xuất và không xuất tất cả các định danh trên. Xem tệp data.go bên dưới. Gói là model.

  • Cấu trúc
    • Cấu trúc Person được xuất ra
    • Cấu trúc company không được xuất ra
  • Phương thức của cấu trúc
    • Phương thức GetAge() của cấu trúc Person được xuất ra
    • Phương thức getName() của cấu trúc Person không được xuất ra
  • Trường của cấu trúc
    • Trường Name của cấu trúc Person được xuất ra
    • Trường age của cấu trúc Person không được xuất ra
  • Hàm
    • Hàm GetPerson() được xuất ra
    • Hàm getCompanyName() không được xuất ra
  • Biến
    • Biến CompanyName được xuất ra
    • Biến companyLocation không được xuất ra

data.go

package model

import "fmt"

var (
    //CompanyName represents the company name
    CompanyName     = "test"
    companyLocation = "somecity"
)

//Person struct
type Person struct {
    Name string
    age  int
}

//GetAge of person
func (p *Person) GetAge() int {
    return p.age
}

func (p *Person) getName() string {
    return p.Name
}

type company struct {
}

//GetPerson get the person object
func GetPerson() *Person {
    p := &Person{
        Name: "test",
        age:  21,
    }
    fmt.Println("Model Package:")
    fmt.Println(p.Name)
    fmt.Println(p.age)
    return p
}

func getCompanyName() string {
    return CompanyName
}

Hãy viết một tệp test.go trong gói model. Xem dưới đây.

test.go

package model

import "fmt"

//Test function
func Test() {
    //STRUCTURE IDENTIFIER
    p := &Person{
        Name: "test",
        age:  21,
    }
    fmt.Println(p)
    c := &company{}
    fmt.Println(c)

    //STRUCTURE'S METHOD
    fmt.Println(p.GetAge())
    fmt.Println(p.getName())

    //STRUCTURE'S FIELDS
    fmt.Println(p.Name)
    fmt.Println(p.age)

    //FUNCTION
    person2 := GetPerson()
    fmt.Println(person2)
    companyName := getCompanyName()
    fmt.Println(companyName)

    //VARIBLES
    fmt.Println(companyLocation)
    fmt.Println(CompanyName)
}

Khi chạy tệp này, nó có thể truy cập được vào tất cả các trường được xuất và không được xuất trong data.go vì cả hai đều nằm trong cùng một gói model. Không có lỗi biên dịch và nó sẽ cho kết quả như sau:

Output:

&{test 21}
&{}
21
test
test
21
Model Package:
test
21
&{test 21}
test
somecity
test

Hãy di chuyển tệp test.go trên đến một gói khác có tên là view. Sau đó chú ý đến kết quả khi chạy 'go build'. Nó sẽ cho ra các lỗi biên dịch. Tất cả các lỗi biên dịch đó đều do không thể truy cập các trường không được xuất ra.

test.go

package view
​​
import "fmt"

//Test function
func Test() {
    //STRUCTURE IDENTIFIER
    p := &model.Person{
        Name: "test",
        age:  21,
    }
    fmt.Println(p)
    c := &model.company{}
    fmt.Println(c)

    //STRUCTURE'S METHOD
    fmt.Println(p.GetAge())
    fmt.Println(p.getName())

    //STRUCTURE'S FIELDS
    fmt.Println(p.Name)
    fmt.Println(p.age)

    //FUNCTION
    person2 := model.GetPerson()
    fmt.Println(person2)
    companyName := model.getCompanyName()
    fmt.Println(companyName)

    //VARIBLES
    fmt.Println(model.companyLocation)
    fmt.Println(model.CompanyName)
}

Output:

test.go:13:3: unknown field 'age' in struct literal of type model.Person
test.go:17:8: cannot refer to unexported name model.company
test.go:17:8: undefined: model.company
test.go:22:15: p.getName undefined (cannot refer to unexported field or method model.(*Person).getName)
test.go:26:15: p.age undefined (cannot refer to unexported field or method age)
test.go:31:17: cannot refer to unexported name model.getCompanyName
test.go:31:17: undefined: model.getCompanyName
test.go:35:14: cannot refer to unexported name model.companyLocation
test.go:35:14: undefined: model.companyLocation