浅谈golang中的代理模式

浅谈golang中的代理模式来自一个大佬的博客,建议食用设计模式不分语言,是一种思维层面的体现,但是不能在不同语言中使用同一套实现(每种语言有不同的特性),比如go,本身是没有继承一说,但是通过结构体的组合来实现语义上的继承。而多态也是通过接口的方式来实现的。下方的图来自于大佬博客,贴在这里方便查看!!!设计原则设计模式结构型模式代理模式首先,我们知道代理模式中分为静态代理和动态代理。静态代理需要在编译前就要写好,而动态代理需要在运行时通过反射来实现方法增强。上述的话,太过粗糙,下面列举一下双方的区别:静态代理:

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

来自一个大佬的博客,建议食用

设计模式不分语言,是一种思维层面的体现,但是不能在不同语言中使用同一套实现(每种语言有不同的特性),比如go,本身是没有继承一说,但是通过结构体的组合来实现语义上的继承。而多态也是通过接口的方式来实现的。

下方的图来自于大佬博客,贴在这里方便查看!!!

设计原则

在这里插入图片描述

设计模式

在这里插入图片描述

结构型模式

代理模式

首先,我们知道代理模式中分为静态代理和动态代理。静态代理需要在编译前就要写好,而动态代理需要在运行时通过反射来实现方法增强。
上述的话,太过粗糙,下面列举一下双方的区别:

静态代理:

  • 代理类实现和目标类相同的接口,每个类都单独编辑一个代理类。
  • 我们需要在代理类中,将目标类中的所有方法都要重新实现,并且为每个方法都附加相似的代码逻辑。
  • 如果要添加方法增强的类不止一个,我们需要对每个类都创建一个代理类。

动态代理:

  • 不需要为每个目标类编辑代理类。
  • 在程序运行时,系统会动态地创建代理类,然后用代理类替换掉原始类。
  • 一般采用反射实现。

代理模式的优点:

  • 代理模式能将代理对象与真实被调用目标对象分离。
  • 在一定程度上降低了系统的耦合性,拓展性好。
  • 可以起到保护目标对象的作用。
  • 可以增强目标对象的功能。

代理的应用场景:

  • 监控
  • 统计
  • 鉴权
  • 限流
  • 事务

静态代理

这里很好看懂,不需过多赘述。

import (
	"fmt"
	"time"
)

//静态代理
//就是对目标类提前实现一个代理类,在调用时使用代理类即可
//代理时需要实现目标类的全部方法

type IUser interface { 
   
	Login(username, password string) error
}

type User struct { 
   
}

func (u *User) Login(username, password string) error { 
   
	//这里就是目标类的函数处理逻辑
	return nil
}

//接下来是代理上述User结构体
type UserProxy struct { 
   
	//有点挟天子以令诸侯,哈哈哈,开个玩笑
	user *User
}

func NewUserProxy(user *User) *UserProxy { 
   
	//返回静态代理类
	return &UserProxy{ 
   
		user: user,
	}
}

func (p *UserProxy) Login(username, password string) error { 
   
	//这里就代理一个程序消耗计时功能
	start := time.Now()
	err := p.user.Login(username, password)
	if err != nil { 
   
		return err
	}
	
	//其实这里用defer栈也可以
	fmt.Printf("调用该程序用时:%v",time.Since(start))
	return nil
}

动态代理

思路:仿照java动态代理的思路,通过InvocationHandler来提供Invoke接口,然后用Proxy结合接口去生成代理类,这个接口需要用户自己实现自有逻辑。

//提供动态调用方法接口
type InvocationHandler interface { 
   
	Invoke(proxy *Proxy, method *Method, args []interface{ 
   }) ([]interface{ 
   }, error)
}

//代理,用来总管代理类的生成
type Proxy struct { 
   
	target  interface{ 
   }        //目标类,后面的类型和java的Object一样
	methods map[string]*Method //map用来装载待增强的不同的方法
	handle  InvocationHandler  //用来暴露统一invoke接口,类似多态
}

//创建新的代理
func NewProxy(target interface{ 
   }, h InvocationHandler) *Proxy { 
   
	typ := reflect.TypeOf(target)          //用来显示目标类动态的真实类型
	value := reflect.ValueOf(target)       //获取目标类的值
	methods := make(map[string]*Method, 0) //初始化目标类的方法map
	//将目标类的方法逐个装载
	for i := 0; i < value.NumMethod(); i++ { 
   
		method := value.Method(i)
		methods[typ.Method(i).Name] = &Method{ 
   value: method}
	}
	return &Proxy{ 
   target: target, methods: methods, handle: h}
}

//代理调用代理方法
func (p *Proxy) InvokeMethod(name string, args ...interface{ 
   }) ([]interface{ 
   }, error) { 
   
	return p.handle.Invoke(p, p.methods[name], args)
}

//用来承载目标类的方法定位和调用
type Method struct { 
   
	value reflect.Value //用来装载方法实例
}

//这里相当于调用原方法,在该方法外可以做方法增强,需要调用者自己实现!!!
func (m *Method) Invoke(args ...interface{ 
   }) (res []interface{ 
   }, err error) { 
   
	defer func() { 
   
		//用来捕捉异常
		if p := recover(); p != nil { 
   
			err = errors.New(fmt.Sprintf("%s", p))
		}
	}()

	//处理参数
	params := make([]reflect.Value, 0)
	if args != nil { 
   
		for i := 0; i < len(args); i++ { 
   
			params = append(params, reflect.ValueOf(args[i]))
		}
	}

	//调用方法
	call := m.value.Call(params)

	//接收返回值
	res = make([]interface{ 
   }, 0)
	if call != nil && len(call) > 0 { 
   
		for i := 0; i < len(call); i++ { 
   
			res = append(res, call[i].Interface())
		}
	}
	return
}

测试代码:

func TestMethod_Invoke(t *testing.T) { 
   
	//这里对活动时长做统计
	people := &People{ 
   }   //创建目标类
	h := new(PeopleProxy) //创建接口实现类
	proxy := NewProxy(people, h)
	//调用方法
	ret, err := proxy.InvokeMethod("Work", "打游戏", "学习")
	if err != nil { 
   
		fmt.Println(err)
	}

	fmt.Println(ret)
}

//目标类
type People struct { 
   
}

func (p *People) Work(content string, next string) string { 
   
	fmt.Println("活动内容是:" + content + ",接下来需要做:" + next)
	return "all right"
}

//用户需要自己实现的增强内容,需要实现InvocationHandler接口
type PeopleProxy struct { 
   
}

//在这里做方法增强
func (p *PeopleProxy) Invoke(proxy *Proxy, method *Method, args []interface{ 
   }) ([]interface{ 
   }, error) { 
   
	start := time.Now()
	defer fmt.Printf("耗时:%v\n", time.Since(start))
	fmt.Println("before method")
	invoke, err := method.Invoke(args...)
	fmt.Println("after method")
	return invoke, err
}

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159492.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月26日 上午10:36
下一篇 2022年7月26日 上午10:36


相关推荐

  • 浅谈SFTP和FTP的区别

    浅谈SFTP和FTP的区别浅谈 SFTP 和 FTP 的区别一 适用场景 我们平时习惯了使用 ftp 来上传下载文件 尤其是很多 Linux 环境下 我们一般都会通过第三方的 SSH 工具连接到 Linux 但是当我们需要传输文件到 Linux 服务器当中 很多人习惯用 ftp 来传输 其实 Linux 默认是不提供 ftp 的 需要你额外安装 FTP 服务器 而且 ftp 服务器端会占用一定的 VPS 服务器资源 其实笔者更建议使用 sftp 代替 ftp 主要因为

    2026年3月16日
    1
  • python小游戏实现代码

    python小游戏实现代码早上逛CSDN首页就见到这么一篇教程。看了一下很有意思,就马上动手实现了一下。看看效果吧:完整代码:#-*-coding:utf-8-*-#1-Importlibraryimport

    2022年7月5日
    26
  • 手把手带你学扣子Coze之大模型节点

    手把手带你学扣子Coze之大模型节点

    2026年3月12日
    3
  • Hunyuan MT1.8B如何做压力测试?Locust模拟高并发教程

    Hunyuan MT1.8B如何做压力测试?Locust模拟高并发教程

    2026年3月13日
    1
  • 如何配置iis使其支持php,iiS PHP,让iiS支持php语言,iiS下配置php运行环境教程图解

    如何配置iis使其支持php,iiS PHP,让iiS支持php语言,iiS下配置php运行环境教程图解iiSPHP 让 iiS 支持 php 语言 iiS 下配置 php 运行环境教程图解 IIs 是 windows 系统下的互联网信息服务 大家主要用于搭建 wEB 服务器 IIs 中已经自带了 AsP 语言的支持 不过现在许多网页系统都是 php 编写的 并且 php 具有更高的运行效率 想让 IIs 支持 php 的话还需要配置 php 运行环境 下面小编就具体分享下 IIs 怎么安装 php 支持 IIs 配置 PHP 三步骤 1 下载 PHP 的文件包

    2026年3月19日
    2
  • JS动画卡顿分析_学会java就能自己设计软件吗

    JS动画卡顿分析_学会java就能自己设计软件吗文章目录动画卡顿分析及解决方法一、卡顿原因分析二、优化的一些方法动画卡顿分析及解决方法一、卡顿原因分析我们所使用的设备大多数的刷新频率都是60HZ,也就是每秒钟会有60个画面来组成一个完整的动画来进行展示。这就要求我们的浏览器对每一帧动画的渲染都在16ms内完成(1秒等于1000ms),一旦渲染时间超过了这个时间段,用户在观看时就会感觉到卡顿。通常,一般人可以分辨的频率也在60HZ左右,所以经常会有人提起打游戏时卡顿,也就是游戏掉帧。二、优化的一些方法1.JavaScript的相关优化:优化Jav

    2022年10月11日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号