思考(四十八):Golang 编程之代理模式

代理模式

代理模式,没接触过的自己度娘下基本概念吧

本文讲下具体应用,并展示下实作中的样子

举例应用说明

代理模式的一个典型应用,就是 AOP模式

AOP模式 通常把程序分为框架层与逻辑层

它的主要特点:

  • 把很多个代理对象组合进 1 个 Context 对象(应用程序上下文对象)
  • Context 对象功能可以横向扩展(即组合更多的代理对象进去)
  • 框架层修改 Context 对象实现,逻辑层代码可以不用做任何更改
  • 框架层通过 Context 对象提供新特性
  • 通过 Context 对象,框架层、逻辑层达成交互

通常的 SDK 框架,都会采用的模式。如 .Net 框架、Java Spring 框架 等等

下面实例分析下 AOP 模式。直接上代码

context.go

context.go

package common

import (
	"context"
	"math/rand"
)

// Context : 应用程序上下文
type Context struct {
	Ctx               context.Context // 常驻功能
	Rand              *rand.Rand      // 常驻功能
	Config            *Config         // 常驻功能
	Log               ILogger         // 常驻功能
	Node              INode           // 常驻功能
	ServerForClient   ITCPServer      // 注册该字段相应接口,才会开启
	ServerForIntranet ITCPServer      // 注册该字段相应接口,才会开启
	Login             ILogin          // 注册该字段相应接口,才会开启
}

代码分析:

  • 上述定义了 1 个应用程序上下文类
  • 从定义可以看出,提供了:
    • golang 的上下文对象功能
    • 随机数生成器
    • 应用程序配置访问接口
    • 日志功能接口
    • 服务节点功能(包括自动接入服务器组、服务发现、服务消息传递等等)
    • 1 个对客户端的 TCP 服务
    • 1 个对服务器组内的 TCP 服务
    • 1 个登陆服务器组的登陆模块接口
  • 显然根据项目需求,还可以继续横向扩展 Context 内容
  • 对于逻辑层程序来说,只需要知道如何使用这些功能,而不需要知道其实现细节
  • 实例化多个 Context ,即可在同一个进程模拟多个应用对象(如果需要的话)

plugin.go

go 语言一种比较好的框架层、逻辑层分离的手段,就是使用插件

  • 框架层, 应用程序 app
  • 逻辑层, 插件
  • 应用程序 app 实现基础公共的功能,并通过 Context 传递给插件

我们来看下插件类:

扫描二维码关注公众号,回复: 8631990 查看本文章

plugin.go


// 无关代码略

// Plugin : 插件组件
type Plugin struct {
	ctx *common.Context
}

// NewPlugin : 实例化
func NewPlugin(ctx *common.Context) *Plugin {
	return &Plugin{ctx: ctx}
}

// 无关代码略

func loadPlugin(ctx *common.Context) {
	once0.Do(func() {
		appName := viper.GetString("app")
		if appName == "" {
			printUsage()
			os.Exit(1)
		}
		so, err := plugin.Open(appName + ".so")
		if err != nil {
			ctx.Log.Errorln(err)
			os.Exit(1)
		}
		
		// 无关代码略
		
		c, err := so.Lookup("Ctx")
		if err != nil {
			ctx.Log.Errorln(err)
			os.Exit(1)
		}
				
		// 无关代码略
		
		*c.(**common.Context) = ctx
	})
}

代码分析:

  • 上面代码中,省略了,无关代码,方便分析
  • 框架层在加载逻辑插件时,把 ctx 对象(应用程序上下文)传递给逻辑层

main.go

main.go

package main

import (
	"fmt"

	"github.com/fananchong/go-xserver/common"
)

// PluginObj : 代表一个插件对象
var PluginObj common.Plugin

// PluginType : 插件类型
var PluginType common.NodeType

// Ctx : 应用程序上下文
var Ctx *common.Context

var login = NewLogin()

func init() {
	fmt.Println("LOAD PLUGIN: LOGIN")
	PluginObj = &Plugin{}
	PluginType = common.Login
}

// Plugin : 插件类
type Plugin struct {
}

// Start : 插件类实现启动
func (plugin *Plugin) Start() bool {
	Ctx.Log.Infoln("Plugin Start")
	login.Start()
	return true
}

// Close : 插件类实现关闭
func (plugin *Plugin) Close() {
	Ctx.Log.Infoln("Plugin Close")
	login.Close()
}

// main : 作为插件包,该函数可以不存在。添加之,是避免 go-lint 烦人的错误提示
func main() {}

代码分析:

  • 这里分析下登陆服的逻辑插件
  • var Ctx *common.Context 应用程序上下文对象,必须定义。框架层加载插件时,会 lookup ,并设置它
  • Ctx.Log.Infoln 直接通过 Context 对象,来使用框架层的日志功能

更多细节

更多细节请参考:

欢迎 Star & Fork

发布了129 篇原创文章 · 获赞 73 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u013272009/article/details/86631083