update tw

This commit is contained in:
chai2010
2015-12-18 10:53:03 +08:00
parent 510c741a6f
commit c66a96ee52
106 changed files with 864 additions and 864 deletions

View File

@@ -1,30 +1,30 @@
## 6.6. 封裝
一個對象的變量或者方法如果對調用方是不可見的話,一般就被定義“封裝”。封裝有時候也被叫做信息隱藏,時也是麫曏對象編程最關鍵的一個方
一個對象的變量或者方法如果對調用方是不可見的話,一般就被定義“封裝”。封裝有時候也被叫做信息隱藏,時也是面向對象編程最關鍵的一個方
Go語言隻有一種控製可見性的手段大寫首字母的標識符會從定義它們的包中被導齣小寫字母的則不會。這種限製包內成員的方式樣適用於struct或者一個類型的方法。因而如果我們想要封裝一個對象我們必鬚將其定義一個struct。
Go語言隻有一種控製可見性的手段大寫首字母的標識符會從定義它們的包中被導齣小寫字母的則不會。這種限製包內成員的方式樣適用於struct或者一個類型的方法。因而如果我們想要封裝一個對象我們必鬚將其定義一個struct。
這也就是前的小節中IntSet被定義struct類型的原因管它隻有一個字段:
這也就是前的小節中IntSet被定義struct類型的原因管它隻有一個字段:
```go
type IntSet struct {
words []uint64
}
```
當然我們也可以把IntSet定義一個slice類型管這樣我們就需要把代碼中所有方法用到的s.words用*s替換掉了
當然我們也可以把IntSet定義一個slice類型管這樣我們就需要把代碼中所有方法用到的s.words用*s替換掉了
```go
type IntSet []uint64
```
管這個版本的IntSet在本質上是一樣的他也可以允許其它包中可以直接讀取編輯這個slice。換句話說相對*s這個達式會齣現在所有的包中s.words隻需要在定義IntSet的包中齣現(譯註:所以還是推薦後者吧的意思)。
管這個版本的IntSet在本質上是一樣的他也可以允許其它包中可以直接讀取編輯這個slice。換句話說相對*s這個達式會齣現在所有的包中s.words隻需要在定義IntSet的包中齣現(譯註:所以還是推薦後者吧的意思)。
這種基於名字的手段使得在語言中最小的封裝單元是package而不是像其它語言一樣的類型。一個struct類型的字段對一個包的所有代碼都有可見性,無論你的代碼是寫在一個函數還是一個方法
這種基於名字的手段使得在語言中最小的封裝單元是package而不是像其它語言一樣的類型。一個struct類型的字段對一個包的所有代碼都有可見性,無論你的代碼是寫在一個函數還是一個方法
封裝提供了三方的優點。首先,因調用方不能直接脩改對象的變量值,其隻需要關註少量的語句且隻要弄懂少量變量的可能的值卽可。
封裝提供了三方的優點。首先,因調用方不能直接脩改對象的變量值,其隻需要關註少量的語句且隻要弄懂少量變量的可能的值卽可。
第二隱藏實現的細節可以防止調用方依賴那些可能變化的具體實現這樣使設計包的程序員在不破壞對外的api情況下能得到更大的自由。
把bytes.Buffer這個類型作例子來考慮。這個類型在做短字符串疊加的時候很常用,所以在設計的時候可以做一些預先的優化,比如提前預留一部分空間,來避免反復的內存分配。又因Buffer是一個struct類型這些額外的空間可以用附加的字節數組來保存且放在一個小寫字母開頭的字段中。這樣在外部的調用方隻能看到性能的提,但不會得到這個附加變量。Buffer和其增長算法我們列在這裏,為了簡潔性稍微做了一些精簡:
把bytes.Buffer這個類型作例子來考慮。這個類型在做短字符串疊加的時候很常用,所以在設計的時候可以做一些預先的優化,比如提前預留一部分空間,來避免反復的內存分配。又因Buffer是一個struct類型這些額外的空間可以用附加的字節數組來保存且放在一個小寫字母開頭的字段中。這樣在外部的調用方隻能看到性能的提,但不會得到這個附加變量。Buffer和其增長算法我們列在這裡,爲了簡潔性稍微做了一些精簡:
```go
type Buffer struct {
@@ -48,7 +48,7 @@ func (b *Buffer) Grow(n int) {
}
```
封裝的第三個優點也是最重要的優點,是阻止了外部調用方對對象內部的值任意地進行脩改。因對象內部變量隻可以被一個包內的函數脩改,所以包的作者可以讓這些函數確保對象內部的一些值的不變性。比如下的Counter類型允許調用方來增加counter變量的值且允許將這個值reset0但是不允許隨便設置這個值(譯註:因壓根就訪問不到)
封裝的第三個優點也是最重要的優點,是阻止了外部調用方對對象內部的值任意地進行脩改。因對象內部變量隻可以被一個包內的函數脩改,所以包的作者可以讓這些函數確保對象內部的一些值的不變性。比如下的Counter類型允許調用方來增加counter變量的值且允許將這個值reset0但是不允許隨便設置這個值(譯註:因壓根就訪問不到)
```go
type Counter struct { n int }
@@ -57,7 +57,7 @@ func (c *Counter) Increment() { c.n++ }
func (c *Counter) Reset() { c.n = 0 }
```
隻用來訪問或脩改內部變量的函數被稱setter或者getter例子如下比如log包的Logger類型對應的一些函數。在命名一個getter方法時我們通常會省略掉前的Get前綴。這種簡潔上的偏好也可以推廣到各種類型的前綴比如FetchFind或者Lookup。
隻用來訪問或脩改內部變量的函數被稱setter或者getter例子如下比如log包的Logger類型對應的一些函數。在命名一個getter方法時我們通常會省略掉前的Get前綴。這種簡潔上的偏好也可以推廣到各種類型的前綴比如FetchFind或者Lookup。
```go
package log
@@ -72,18 +72,18 @@ func (l *Logger) Prefix() string
func (l *Logger) SetPrefix(prefix string)
```
Go的編碼風格不禁止直接導齣字段。當然一旦進行了導齣就沒有辦法在保API兼容的情況下去除對其的導齣所以在一開始的選擇一定要經過深思熟慮且要考慮到包內部的一些不變量的保,未來可能的變化,以及調用方的代碼質量是否會因包的一點脩改而變差。
Go的編碼風格不禁止直接導齣字段。當然一旦進行了導齣就沒有辦法在保API兼容的情況下去除對其的導齣所以在一開始的選擇一定要經過深思熟慮且要考慮到包內部的一些不變量的保,未來可能的變化,以及調用方的代碼質量是否會因包的一點脩改而變差。
封裝不總是理想的。
雖然封裝在有些情況是必要的但有時候我們也需要暴露一些內部內容比如time.Duration將其現暴露一個int64數字的納秒使得我們可以用一般的數值操作來對時間進行對比甚至可以定義這種類型的常量
封裝不總是理想的。
雖然封裝在有些情況是必要的但有時候我們也需要暴露一些內部內容比如time.Duration將其現暴露一個int64數字的納秒使得我們可以用一般的數值操作來對時間進行對比甚至可以定義這種類型的常量
```go
const day = 24 * time.Hour
fmt.Println(day.Seconds()) // "86400"
```
另一個例子將IntSet和本章開頭的geometry.Path進行對比。Path被定義一個slice類型這允許其調用slice的字方法來對其內部的points用range進行迭代遍在這一點上IntSet是沒有辦法讓你這做的。
另一個例子將IntSet和本章開頭的geometry.Path進行對比。Path被定義一個slice類型這允許其調用slice的字方法來對其內部的points用range進行迭代遍在這一點上IntSet是沒有辦法讓你這做的。
這兩種類型決定性的不geometry.Path的本質是一個坐標點的序列不多也不少我們可以預見到之後也不會給他增加額外的字段所以在geometry包中將Path暴露一個slice。相比之下IntSet僅僅是在這用了一個[]uint64的slice。這個類型還可以用[]uint類型來示,或者我們甚至可以用其它完全不的佔用更小內存空間的東西來示這個集,所以我們可能還會需要額外的字段來在這個類型中記元素的個數。也正是因這些原因我們讓IntSet對調用方透明。
這兩種類型決定性的不geometry.Path的本質是一個坐標點的序列不多也不少我們可以預見到之後也不會給他增加額外的字段所以在geometry包中將Path暴露一個slice。相比之下IntSet僅僅是在這用了一個[]uint64的slice。這個類型還可以用[]uint類型來示,或者我們甚至可以用其它完全不的佔用更小內存空間的東西來示這個集,所以我們可能還會需要額外的字段來在這個類型中記元素的個數。也正是因這些原因我們讓IntSet對調用方透明。
在這章中,我們學到了如何將方法與命名類型進行組閤,併且知道了如何調用這些方法。管方法對於OOP編程來說至關重要但他們隻是OOP編程的半邊天。了完成OOP我們還需要接口。Go的接口會在下一章中介紹。
在這章中,我們學到了如何將方法與命名類型進行組合,並且知道了如何調用這些方法。管方法對於OOP編程來說至關重要但他們隻是OOP編程的半邊天。了完成OOP我們還需要接口。Go的接口會在下一章中介紹。