2015年12月31日 星期四

golang 多型運用心得

golang 多型運用心得
===
一開始想找一個kay-value的儲存方式,先找到了一個gkvlite的開源項目。經過測試以後也覺得應該適用,於是使用了之後發現到它轉成json的方式好像不如預期。
後來想一想,那倒不如就用map轉json的方式存就好了,這樣也沒有開源bug的風險,自己有bug也好除錯。但是已經實做gkvlite下去了,也幫它寫好了struct以及一些包裝函數。
這時候又思考,要換成json的話需要打掉重練嗎?還是應該弄一個介面出來變成多形的方式,讓兩種方式並存。即使現在覺得gkvlite可能永遠不用,但哪怕有一天還會用到。
心中懶惰的想法這時又油然而生,砍掉重練比較輕鬆啦,不要搞甚麼多型累死了。另一方面較為專業的想法會想要累積這兩種儲存方式,以便未來再重複使用。
我想這個情況就是利用多形是最好時候,因此我把心中的懶惰蟲給抓出來,面對它吧!以下是多形重構過程:

type BackupDB struct{
f *os.File
c *gkvlite.Collection
s *gkvlite.Store
notify chan BackupNote
}
func openBackupDB( dbfile string ) *BackupDB {
...
}
func ( db *BackupDB )closeStore() {
...
}
func ( db *BackupDB )flushStore() {
...
}

其實原本沒有這麼整齊每一個函數都有用到receiver,而是為了要多形而先補齊這樣抽像化的結構。
花一點時間整理好之後就可以開始來建立另一個以json儲存的方式了


type BackupJson struct{
f *os.File
}
func openBackupJson( dbfile string ) *BackupJson {
bj := &BackupJson{}
f,err := os.Create( dbfile )
if err != nil{
Error(err)
return nil
}
bj.f = f
return bj
}
func ( bj *BackupJson )closeStore() {
}
func ( bj *BackupJson )flushStore() {
}
func ( bj *BackupJson )deleteKey( key *string ) bool{
wasDeleted := true
return wasDeleted
}
func ( bj *BackupJson )setKey( key *string ) bool{
wasSet := true
return wasSet
}


很快地寫完函數規格但還不能動的版本,兩種方法都有一樣的函數宣告,只有receiver不同,這樣子正洽好就是golang的多形規則。這時候就可以宣告一個interface


type KeyStore interface{
setKey( key *string , value *string ) bool
deleteKey( key *string ) bool
closeStore()
flushStore()
}

最後一步就是在使用KeyStore的地方兩個方法擇一執行,使用指派的方式去轉成interface操作


var ks KeyStore
if ( DB_SELECT == JSON ){
ks = KeyStore( openBackupJson( FILELIST_PATH ) )
}else{
ks = KeyStore( openBackupDB( FILELIST_PATH ) )
}
  ks.setKey( &file , &value )
ks.closeStore()


這樣,只要指派不同的結構,就可以將兩個方法給結合起來,之後只要面對KeyStore介面就可以了。
過去C語言裡面會用#ifdef來做這個區分,很偷懶很難看但是很實用。但是用#ifdef也就宣告了兩邊的程式碼互相無關,也不會再為了對方修改了。
其實是因為go裡面如果用不到的func會是個錯誤,從這邊為源頭,想要讓自己的code更好才會想要再進一步用多型,所以go的語言內涵就包含了除去人們懶惰的習慣的功能...









-

沒有留言: