使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用

这篇具有很好参考价值的文章主要介绍了使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在诸如广告、推荐等系统中,我们往往会涉及过滤、召回和排序等过程。随着系统业务变得复杂,代码的耦合和交错会让项目跌入难以维护的深渊。于是模块化设计是复杂系统的必备基础。这篇文章介绍的业务框架脱胎于线上多人协作开发、高并发的竞价广告系统,在实践中不停被优化,直到易于理解和应用。

基础组件

Handler

在系统中,我们定义一个独立的业务逻辑为一个Handler。
比如过滤“机型”信息的逻辑可以叫做DeviceFilterHandler,排序的逻辑叫SortHandler。
Handler的实现也很简单,只要实现frame.HandlerBaseInterface接口和它对应的方法即可(见github):

package main

import (
	"fmt"
	"ghgroups/frame"
	ghgroupscontext "ghgroups/frame/ghgroups_context"
	"reflect"
)

type ExampleHandler struct {
	frame.HandlerBaseInterface
}

func NewExampleHandler() *ExampleHandler {
	return &ExampleHandler{}
}

// ///
// ConcreteInterface
func (e *ExampleHandler) Name() string {
	return reflect.TypeOf(*e).Name()
}

// ///
// HandlerBaseInterface
func (e *ExampleHandler) Handle(*ghgroupscontext.GhGroupsContext) bool {
	fmt.Printf("run %s", e.Name())
	return true
}

ConcreteInterface

在系统中,我们要求每个组件都要有名字。这样我们可以在配置文件中指定它在流程中的具体位置。
组件通过继承接口ConcreteInterface,并实现其Name方法来暴露自己的名称。它可以被写死(如上例),也可以通过配置文件来指定(见后续案例)。

type ConcreteInterface interface {
	Name() string
}

HandlerBaseInterface

处理业务逻辑的代码需要在Handle(context *ghgroupscontext.GhGroupsContext) bool中实现的。上例中,我们只让其输出一行文本。
这个方法来源于HandlerBaseInterface接口。

type HandlerBaseInterface interface {
	ConcreteInterface
	Handle(context *ghgroupscontext.GhGroupsContext) bool
}

因为HandlerBaseInterface 继承自ConcreteInterface ,所以我们只要让自己构建的Handler继承自HandlerBaseInterface,并实现相应方法即可。

应用

一般一个复杂的业务不能只有一个Handler,但是为了便于方便讲解,我们看下怎么运行只有一个Handler的框架(见github)。

package main

import (
	"fmt"
	"ghgroups/frame"
	"ghgroups/frame/constructor"
	ghgroupscontext "ghgroups/frame/ghgroups_context"
	"ghgroups/frame/utils"
	"reflect"
)

func main() {
	constructor := utils.BuildConstructor("")
	constructor.Register(reflect.TypeOf(ExampleHandler{}))
	mainProcess := reflect.TypeOf(ExampleHandler{}).Name()
	run(constructor, mainProcess)
}

func run(constructor *constructor.Constructor, mainProcess string) {
	if err := constructor.CreateConcrete(mainProcess); err != nil {
		fmt.Printf("%v", err)
	}
	if someInterfaced, err := constructor.GetConcrete(mainProcess); err != nil {
		fmt.Printf("%v", err)
	} else {
		if mainHandlerGroup, ok := someInterfaced.(frame.HandlerBaseInterface); !ok {
			fmt.Printf("mainHandlerGroup %s is not frame.HandlerBaseInterface", mainProcess)
		} else {
			context := ghgroupscontext.NewGhGroupsContext(nil)
			// context.ShowDuration = true
			mainHandlerGroup.Handle(context)
		}
	}
}

在main函数中,我们需要向对象构建器constructor注册我们写的Handler。然后调用run方法,传入构建器和需要启动的组件名(mainProcess)即可。运行结果如下

ExampleHandler
run ExampleHandler

第一行是框架打印的流程图(目前只有一个),第二行是运行时ExampleHandler的Handle方法的执行结果。

HandlerGroup

HandlerGroup是一组串行执行的Handler。
使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用,Golang,golang,开发语言,后端

框架底层已经实现好了HandlerGroup的代码,我们只要把每个Handler实现即可(Handler的代码可以前面的例子)。
然后在配置文件中,配置好Handler的执行顺序:

name: handler_group_a
type: HandlerGroup
handlers: 
  - ExampleAHandler
  - ExampleBHandler

应用

部分代码如下(完整见github)

package main

import (
	"fmt"
	"ghgroups/frame"
	"ghgroups/frame/constructor"
	constructorbuilder "ghgroups/frame/constructor_builder"
	"ghgroups/frame/factory"
	ghgroupscontext "ghgroups/frame/ghgroups_context"
	"os"
	"path"
	"reflect"
)

func main() {
	factory := factory.NewFactory()
	factory.Register(reflect.TypeOf(ExampleAHandler{}))
	factory.Register(reflect.TypeOf(ExampleBHandler{}))

	runPath, errGetWd := os.Getwd()
	if errGetWd != nil {
		fmt.Printf("%v", errGetWd)
		return
	}
	concretePath := path.Join(runPath, "conf")
	constructor := constructorbuilder.BuildConstructor(factory, concretePath)
	mainProcess := "handler_group_a"

	run(constructor, mainProcess)
}

这次对象构建器我们需要使用constructorbuilder.BuildConstructor去构建。因为其底层会通过配置文件所在的文件夹路径(concretePath )构建所有的组件。而在此之前,需要告诉构建器还有两个我们自定义的组件(ExampleAHandler和ExampleBHandler)需要注册到系统中。于是我们暴露出对象工厂(factory )用于提前注册。
运行结果如下

handler_group_a
        ExampleAHandler
        ExampleBHandler
run ExampleAHandler
run ExampleBHandler

前三行是配置文件描述的执行流程。后两行是实际执行流程中的输出。

AsyncHandlerGroup

AsyncHandlerGroup是一组并行执行的Handler。
使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用,Golang,golang,开发语言,后端
和HandlerGroup一样,框架已经实现了AsyncHandlerGroup的底层代码,我们只用实现各个Handler即可。
有别于HandlerGroup,它需要将配置文件中的type设置为AsyncHandlerGroup。

name: async_handler_group_a
type: AsyncHandlerGroup
handlers: 
  - ExampleAHandler
  - ExampleBHandler

应用

使用的代码和HandlerGroup类似,具体见github。
执行结果如下

async_handler_group_a
        ExampleAHandler
        ExampleBHandler
run ExampleBHandler
run ExampleAHandler

Layer

Layer由两部分组成:Divider和Handler。Handler是一组业务逻辑,Divider用于选择执行哪个Handler。
使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用,Golang,golang,开发语言,后端

Divider

不同于Handler,Divider需要继承和实现DividerBaseInterface接口。

type DividerBaseInterface interface {
	ConcreteInterface
	Select(context *ghgroupscontext.GhGroupsContext) string
}

Select方法用于填充业务逻辑,选择该Layer需要执行的Handler的名称。下面是Divider具体实现的一个样例(见github)。

package main

import (
	"ghgroups/frame"
	ghgroupscontext "ghgroups/frame/ghgroups_context"
	"reflect"
)

type ExampleDivider struct {
	frame.DividerBaseInterface
}

func NewExampleDivider() *ExampleDivider {
	return &ExampleDivider{}
}

// ///
// ConcreteInterface
func (s *ExampleDivider) Name() string {
	return reflect.TypeOf(*s).Name()
}

// ///
// DividerBaseInterface
func (s *ExampleDivider) Select(context *ghgroupscontext.GhGroupsContext) string {
	return "ExampleBHandler"
}

应用

每个Layer都要通过配置文件来描述其组成。相较于HandlerGroup,由于它不会执行所有的Handler,而是要通过Divider来选择执行哪个Handler,于是主要是新增Divider的配置项。

name: layer_a
type: Layer
divider: ExampleDivider
handlers: 
  - ExampleAHandler
  - ExampleBHandler

具体执行的代码见github。我们看下运行结果

layer_a
        ExampleDivider
        ExampleAHandler
        ExampleBHandler
run ExampleBHandler

可以看到它只是执行了Divider选择的ExampleBHandler。

LayerCenter

LayerCenter是一组串行执行的Layer的组合。
使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用,Golang,golang,开发语言,后端
在使用LayerCenter时,我们只要实现好每个Layer,然后通过配置文件配置它们的关系即可。

type: LayerCenter
name: layer_center
layers: 
  - layer_a
  - layer_b

应用

具体代码和前面类似,可以见github。
运行结果如下

layer_center
        layer_a
                ExampleADivider
                ExampleA1Handler
                ExampleA2Handler
        layer_b
                ExampleBDivider
                ExampleB1Handler
                ExampleB2Handler
run ExampleA2Handler
run ExampleB1Handler

可以看到每个Layer选择了一个Handler执行。

源码见github。文章来源地址https://www.toymoban.com/news/detail-624074.html

到了这里,关于使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 推荐一款好用的开源视频播放器(免费无广告)

    mpv是一个自由开源的媒体播放器,它支持多种音频和视频格式,并且具有高度可定制性。mpv的设计理念是简洁、高效和功能强大。 软件特点: 1. 开源、跨平台。可以在WindowsLinuxMacOSBSD等系统上使用,完全免费无广告。Windows版解压即用,绿色便携。 2. 兼容性好。支持绝大多

    2024年02月11日
    浏览(34)
  • 推荐几款小众且无广告的软件,你值得拥有

    你是否喜欢一些小众且无广告的软件?如果是的话,我这边有一些给你推荐的。 ​ EyeLoveU是一款免费的护眼软件,可以在你使用电脑一段时间后,提醒你该让眼睛休息。EyeLoveU是一种智能的眼睛保护程序,根据你的鼠标和键盘的操作动作,来判断你的电脑使用时间。它还提供

    2024年02月14日
    浏览(30)
  • 推荐5款体积小、无广告、超实用的办公软件

    大家好,我又来啦,今天给大家带来的几款软件,共同特点都是无广告、超实用,大家观看完可以自行搜索下载哦。 Wireshark 是一款开源的网络分析工具,它可以让你捕获和浏览网络上的数据包,让你深入了解网络的运行情况。它界面丰富,支持多种协议,可以过滤和搜索数

    2024年02月03日
    浏览(26)
  • 好用的电视盒子软件推荐:无广告看电视我选这两款

    虽然现在智能电视基本已经普及,大家也都有使用智能电视的意识,但无奈它价格昂贵啊……所以,其实你知道的,我们中的大部分人还是会选择买个小的电视盒子,然后基本能够达到和智能电视一样的体验效果,甚至能折腾出永久免费的电视机顶盒!(当然,想要完全媲美

    2024年02月11日
    浏览(51)
  • 适用于快速开发应用的Golang二次框架

    适用于快速开发应用的Golang二次框架。 GinSkeleton 项目简介 1.这是一个基于go语言gin框架的web项目骨架,专注于前后端分离的业务场景,其目的主要在于将web项目主线逻辑梳理清晰,最基础的东西封装完善,开发者更多关注属于自己的的业务即可。 2.本项目骨架封装了以tb_users表

    2024年02月07日
    浏览(33)
  • 仿造问卷星--开发一套调查问卷设计工具(3/3)--完整流程

    1,定义一个结果的对象: id,name和questions分别对应问卷id,问卷名称和问卷题目。 2,结果赋值 用户点击生成问卷按钮时, 分别从id和name文本框中获取值 --赋值给resultObj 将上节课拿到的question赋值给刚刚定义的对象: 打印输出结果: json结果: 3,pretty-print-json的使用 引入

    2023年04月11日
    浏览(39)
  • 仿造问卷星--开发一套调查问卷设计工具(1/3)--完整流程

    一,开发前的准备 第一步,初始化项目 创建package.json 首先,新建一个空文件夹项目,在空文件上按shift键同时鼠标右击,打开命令终端窗口 第二步,安装项目依赖 Parcel 快速部署工具,官网:https://parceljs.org/docs/ Parcel是一款极速零配置WEB应用打包工具,快速、几乎零配置是

    2023年04月08日
    浏览(30)
  • 使用 docker desktop 配置(window环境下适用Linux)

    环境 win11 专业版 使用window环境安装docker ,配置常用容器。 出现问题,nginx 配置文件无法更改,使用自带powerShell 编辑器,vim命令无法使用    

    2024年02月11日
    浏览(34)
  • apple pencil平替笔哪个好用?适用于绘画的电容笔推荐

    由于ipad的版本一直在升级,其功能也在增加,其功能已经达到了与手提电脑相媲美的程度。而且随着科技的发展,ipad也不仅仅是一个娱乐的工具,更是一个可以用来学习、画画、工作的强大工具。想要提高生产力,那么电容笔就是必不可少的。在Apple Pencil的热度下,国内的

    2024年02月12日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包