接口就是一种规范, 只要遵循规范就可以使用其方法做多态操作
使用步骤:
1.在接口中定义方法
2.需要不同的实现
3.统一管理这些实现
以一个负载均衡为例
创建实例(主机)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就是一个集中入口, 可称之为管家