Golang物件導向程式設計之繼承&虛基類【組合&介面】

吳德寶AllenWu發表於2018-08-10

[TOC]

Golang物件導向程式設計之繼承&虛基類【組合&介面】

201808

相關說明

Golang裡面沒有像C++一樣有繼承相關的概念,但是我們卻可以實現繼承相關的用法,這就要用到struct、interface這兩個結構。

Golang裡面有組合的概念,也就是一個struct 裡面可以包含一個或者多個struct,struct可以近似理解為物件導向程式設計中的class,但是不能等同,有很多區別。如果一個struct實現了某個介面的所有方法,那麼只要是包含這個struct的所有其他struct也都是實現了這個介面的所有方法

實現 class 類

要想實現class類的用法,那麼就要用到struct結構,通過給定struct定義某個成員變數或成員方法就可以實現類的方法

  1. 通過type struct 定義一個struct【類】

    type rsaSecurity struct {
    }
    複製程式碼
  2. 再定義一個這個類的變數,也就是物件

    var RsaSecuritySrv rsaSecurity
    複製程式碼

    類似於建構函式的定義,也可以通過new一個物件來使用,二選一。

  3. 實現一個這個struct類的方法,需要注意要顯示的宣告所屬物件,即(rs *rsaSecurity)

    // 加密
    func (rs *rsaSecurity) RsaEncrypt(origData []byte) ([]byte, error) {
    	//解密pem格式的公鑰
    	block, _ := pem.Decode(publicKey)
    	if block == nil {
    		return nil, errors.New("public key error")
    	}
    	// 解析公鑰
    	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    	if err != nil {
    		return nil, err
    	}
    	// 型別斷言
    	pub := pubInterface.(*rsa.PublicKey)
    	//加密
    	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
    }
    複製程式碼

    注意這裡是否使用指標,在於是否能夠是否需要徹底修改成員變數的值。

  4. 在任何需要呼叫這個成員方法的時候,通過物件來呼叫

    func main() {
    
    	data, _ := RsaSecuritySrv.RsaEncrypt([]byte(encrypt))
    }
    複製程式碼

實現繼承

直接上程式碼如下,很簡單,主要就是一個struct裡面包含一個匿名的struct,也就是通過匿名組合來實現

package main

import (
	"fmt"
)

// 【基類】
//定義一個最基礎的struct類MsgModel,裡面包含一個成員變數msgId
type MsgModel struct {
	msgId   int
	msgType int
}

// MsgModel的一個成員方法,用來設定msgId
func (msg *MsgModel) SetId(msgId int) {
	msg.msgId = msgId
}

func (msg *MsgModel) SetType(msgType int) {
	msg.msgType = msgType
}

//【子類】
// 再定義一個struct為GroupMsgModel,包含了MsgModel,即組合,但是並沒有給定MsgModel任何名字,因此是匿名組合
type GroupMsgModel struct {
	MsgModel

	// 如果子類也包含一個基類的一樣的成員變數,那麼通過子類設定和獲取得到的變數都是基類的
	msgId int
}

func (group *GroupMsgModel) GetId() int {
	return group.msgId
}

/*
func (group *GroupMsgModel) SetId(msgId int) {
	group.msgId = msgId
}
*/

func main() {
	group := &GroupMsgModel{}

	group.SetId(123)
	group.SetType(1)

	fmt.Println("group.msgId =", group.msgId, "\tgroup.MsgModel.msgId =", group.MsgModel.msgId)
	fmt.Println("group.msgType =", group.msgType, "\tgroup.MsgModel.msgType =", group.MsgModel.msgType)
}


複製程式碼

實現虛基類的用法

Golang可以通過匿名組合來實現繼承。

Golang可以interface + struct來實現虛基類的用法,必須要實現interface中定義的方法。

1,定義一個interface介面MsgModel,包含了一些方法。

type MsgModel interface {
    Persist(context context.Context, msg interface{}) bool
    PersistOnSensitive(context context.Context, session_type, level, SensitiveStatus int32, msg interface{}) bool
}
複製程式碼

3,定義一個型別msgModelImpl,用來實現介面型別

定義一個struct用來實現介面型別
type msgModelImpl struct{}


定義一個變數MsgModelImpl等於msgModelImpl,相當於可以通過MsgModelImpl來呼叫msgModelImpl的成員
var MsgModelImpl = msgModelImpl{}

實現介面的兩個方法
func (m msgModelImpl) Persist(context context.Context, msgIface interface{}) bool {
// 具體實現省略
}

func (m msgModelImpl) UpdateDbContent(context context.Context, msgIface interface{}) bool {
// 具體實現省略
}

複製程式碼

4, 定義一個struct型別的msgService,包含上述介面型別MsgModel,相當於組合了。這樣的話,這個型別就需要要實現介面方法。

type msgService struct {
   msgModel MsgModel
}
複製程式碼

5, 再定義一個變數MsgService,首字母大寫,並且賦值為msgService物件,同時給成員msgModel賦值為上述已經實現了介面的struct物件MsgModelImpl。

將上述已經實現介面型別的型別(MsgModelImpl) 賦值給此變數(此變數並且要是包含了介面型別的型別), 然後這個變數就可以供外部呼叫
var  MsgService = msgService{
        msgModel:  MsgModelImpl,
}
複製程式碼

6, 通過MsgService呼叫介面方法

7, 小結:

  • MsgModel 是一個interface
    • interface 是一組抽象方法(未具體實現的方法/僅包含方法名引數返回值的方法)的集合
  • msgModelImpl是一個struct,它實現了MsgModel這個interface的所有方法
    • 如果實現了 interface 中的所有方法,即該類/物件就實現了該介面
  • MsgModelImpl是msgModelImpl這個struct的物件
  • msgService是一個struct,它包含了MsgModel,相當於組合
  • MsgService是msgService這個struct的物件,並對成員變數賦值

相關文章