go 接口使用(适配器模式)

接口就是一种规范, 只要遵循规范就可以使用其方法做多态操作

使用步骤:

1.在接口中定义方法

2.需要不同的实现

3.统一管理这些实现

以一个负载均衡为例

go 接口使用(适配器模式)_第1张图片

 创建实例(主机)instance.go:

package balance
import "strconv"

/*用于表示主机实例*/
type Instance struct {
    host string			// ip
    port int			// 端口
}

/*创建实例*/
func CreateInstance(param_host string, param_port int) (instance *Instance) {
    return &Instance {
        host : param_host,
        port : param_port,
    }
}

/*获取host*/
func (ins *Instance) GetHost() string{
    return ins.host
}

/*获取port*/
func (ins *Instance) GetPort() int{
    return ins.port
}

/*实现fmt的String方法, 格式化输出实例*/
func (ins *Instance) String() (str string) {
    str = ins.host + "-->" + strconv.Itoa(ins.port)
    return
}

创建接口balance.go:

package balance

/*定义接口, 用于后台 主机均衡调用 统一接口*/
type Balance interface {
    // 传入多个主机实例 和可选的参数, 返回一个实例 和可能发生的错误
    // 具体返回的实例根据不同的实现来获取
    DoBalance([]*Instance, ...string) (*Instance, error)
}

创建随机实现random.go:

package balance
import (
    "math/rand"
    "errors"
)

/*使用随机算法, 获取实例, 即随机获取到一个实例*/

type Random struct {
}

/*实现DoBalance方法*/
func (r *Random) DoBalance(i []*Instance, keys...string) (oneInstance *Instance, err error) {
    lens := len(i)
    // 传入的实例个数必须要大小1
    if lens == 0 {	
        err = errors.New("must have one instance")
        return
    }

    // 从已有的实例中随机一个
    index := rand.Intn(lens)
    oneInstance = i[index]
    return
}

/*初始化, 调用注册方法, 将此实现注册到集中管理*/
func init() {
    RegistBalance("random", &Random{})
}

创建轮循实现roundrobin.go:

package balance
import (
    "fmt"
)

type Roundrobin struct {
}

var index = 0

/*实现轮循算法*/
func (r *Roundrobin) DoBalance(insts []*Instance, keys...string) (inst *Instance, err error) {
    // 切片长度
    lens := len(insts) 
    if lens < 1 {
        err = fmt.Errorf("传入实例的个数为%d, 它需要大于或等于1", lens)
    }
    inst = insts[index]
    if index == lens -1 {
        index = 0
    } else {
        index ++
    }
    return
}

/*初始化注册到管家map中*/
func init() {
    RegistBalance("roundrobin", &Roundrobin{})
}

创建实现的管家mgr.go:

package balance
import (
    "fmt"
)

/*统一管理实现均衡调度的实现*/
type BalanceManager struct {
    allBalance map[string]Balance
}

/*创建全局变量*/
var mgr = BalanceManager {
    allBalance : make(map[string]Balance),
}

/*将不同的实现注册到map中*/
func RegistBalance(name string, b Balance) {
    mgr.allBalance[name] = b
}

/*统一处理实现, 去调用DoBalance, 外部只需调用此方法即可, 不用调用具体的实现, 这个方法会判断调用具体实现*/
func ManageBalance(name string, insts []*Instance) (inst *Instance, err error) {
    // 从mgr中 判断是否有参数name的实现
    balance, ok := mgr.allBalance[name]
    if !ok {
        err = fmt.Errorf("Has no %s balance", name)
        return
    }
    fmt.Printf("use %s balance\n", name)
    // 去调用各自 真正的 实现
    inst, err = balance.DoBalance(insts)
    return
}

main中可以使用main.go:

package main
import (
    "fmt"
    "day7/balance"
    "strconv"
    "math/rand"
    "time"
)
func main() {
    /*创建切片 -- 主机*/
    var instances []*balance.Instance

    /*创建主机*/
    for i:=0;i<10; i++ {
        var instance *balance.Instance
		
        host := "192.168." + strconv.Itoa(rand.Intn(255)) + "." +strconv.Itoa(rand.Intn(255))
        port :=  8080
        instance = balance.CreateInstance(host, port) 
        instances = append(instances, instance)
    }
    fmt.Println(instances)
	
    var str = "random"
    // var str = "roundrobin"
    // var str = "hashBalance"

    for {
        // 统一调用管家中的方法, 返回实例
        oneInstance, err := balance.ManageBalance(str, instances)
        // 如果传入的实例个数为0, 则提示: must have one instance
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println(oneInstance)
        time.Sleep(time.Second)
    }
}

扩展一个实现hash.go:

如上的balance作为一个库, 不需要修改任何代码

在此前题下, 要扩展一个hash一致性实现, 如下模拟一个简单的hash一致性实现

package main

/*扩展均衡调度的算法, 不需要修改balance任何代码*/
import (
    "fmt"
    "day7/balance"
    "math/rand"
    "hash/crc32"
)

type HashBalance struct {
}

/*实现hash一致算法实现*/
func (r *HashBalance) DoBalance(insts []*balance.Instance, keys...string) (inst *balance.Instance, err error) {
    lens := len(insts)
    if lens == 0 {
        err = fmt.Errorf("No backend instance")
        return
    }

    // 在此就使用一个随机的字符串作为key
    var defaultKey string = fmt.Sprintf("%d", rand.Int())
    // 取值为第一个key
    if len(keys) > 0 {
        defaultKey = keys[0]
    }

    crcTable := crc32.MakeTable(crc32.IEEE)
    // 计算hash值
    hashVal := crc32.Checksum([]byte(defaultKey), crcTable)
    // fmt.Println(hashVal)
    // 就这样简易操作吧
    index := int(hashVal) % lens
    inst = insts[index]
    return
}

/*初始化注册到管家map中*/
func init() {
    balance.RegistBalance("hashBalance", &HashBalance{})
}

注: hash一致性是根据用户ip与主机ip做映射处理, 若要真正实现hash一致性需要比较复杂的处理

mgr.go中统一管理不同的实现, 使用者, 只需要处理mgr.go中的DoBalance方法

DoBalance会自动判断调用不同的实现

所以mgr.go就是一个集中入口, 可称之为管家

你可能感兴趣的:(go 接口使用(适配器模式))