浅谈golang中的代理模式
来自一个大佬的博客,建议食用
设计模式不分语言,是一种思维层面的体现,但是不能在不同语言中使用同一套实现(每种语言有不同的特性),比如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
}
浅谈golang中的代理模式相关推荐
- 浅谈开发中的MVVM模式及与MVP和MVC的区别
2019独角兽企业重金招聘Python工程师标准>>> 我记得前段时间分享了一篇文章< 浅谈Andorid开发中的MVP模式>(点击可跳转),反响不错,为了进一步介绍MV ...
- 浅谈java的静态代理模式
嗨喽-小伙伴们XX好呀, 本章我们来介绍,java中出现的静态代理模式. 代理,对应于英语单词-----Proxy,从字面上理解,就是在实现代理目标(Target)所有的需求的同时,还能够实现代理目标 ...
- 浅谈自己对Java代理模式的理解--即为什么要用怎么用
首先,国际惯例,上Java代理模式的定义: Java代理模式:对其他对象提供一种代理以控制对这个对象的访问. 定义很简单,就一句话,怎么去理解,不急,先听一个小故事: 故事 ...
- 浅谈安卓中的MVP模式
端午放假,天气下雨,于是乎在家撸一下博客,本篇博客将为大家解析MVP模式在安卓中的应用. 本文将从以下几个方面对MVP模式进行讲解: 1. MVP简介 2. 为什么使用MVP模式 3. MVP模 ...
- 浅谈Android中的MVP与动态代理的结合
浅谈Android中的MVP与动态代理的结合 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在Android开发平台上接触MVP足足算起来大概已经有一个年头左右.从最开始到现在经 ...
- 理解各种设计模式原则及区别丨浅谈Nginx中核心设计模式-责任链模式丨C++后端开发丨Linux服务器开发丨web服务器
理解各种设计模式原则及区别丨浅谈Nginx中核心设计模式-责任链模式 1. 开闭.单一职责.里氏替换.接口隔离等设计原则 2. 随处可见的模板方法 3. nginx中核心设计模式 责任链模式 4. 责 ...
- 浅谈caffe中train_val.prototxt和deploy.prototxt文件的区别
浅谈caffe中train_val.prototxt和deploy.prototxt文件的区别 标签: caffe深度学习CaffeNet 2016-11-02 16:10 1203人阅读 评论(1) ...
- python的re2和re区别_浅谈Python中re.match()和re.search()的使用及区别
1.re.match()fvk免费资源网 re.match()的概念是从头匹配一个符合规则的字符串,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None.fvk免费资源网 包含的参数如下: ...
- 浅谈Hibernate中的几个查询
浅谈Hibernate中的几个查询 一.load和get方法的区别 1.load在查询时,先从一级缓存中寻找与数据索引对应的实体对象,然后构建并返回一个代理对象,当我们真正使用这个代理对象的时候,这时 ...
最新文章
- spring bean xml 调用方法_Spring通过Xml方式注册Bean的几处关键实现点
- 【Linux】一步一步学Linux——telinit命令(144)
- [Java基础]Set集合概述和特点
- python变量如何用循环定义_Python学习日记1(变量定义,分支,循环)
- [转]把人当成一个公司来经营,心就不会那么累
- python scapy sniffer停止抓包_如果没有收到数据包,如何告诉scapy sniff()停止?
- python, 面向对象编程Object Oriented Programming(OOP)
- php 绘图 jpeg,PHP gd库增加jpeg支持
- Apache Pulsar的多租户消息系统
- 游戏设计阻力探秘之扩展空间
- 实例学习ZMODEM文件传输协议
- linux memtest错误但没死机,LINUX系统无故死机,系统日志报错如下,各位帮忙看看是因为什么...
- hive建表语句 增加字段、分区基础操作
- 关于GomezPeer赚钱的可行性调查
- 查找恶意的TOR中继节点
- 给大家安利一个Python版本的记忆翻牌小游戏!上才艺!!
- 一分钟快速把一篇论文后面的参考文献全部下载下来
- 计算机应用基础全解,第三章习题-ddg全解.doc
- ubuntu20.04离线安装python2.7.17
- 怎样修改图纸中单个图块的基点 ?
热门文章
- 【Vue】组件间传值的三种方式:父传子,子传父,非父子传值
- 淘宝商品数据清洗及预处理
- 怎么计算机会成本,机会成本计算公式,实例解读机会成本
- jquery 堆栈溢出_带有jQuery和CSS3的漂亮照片堆栈库
- 中国股市最“暴利”时代,而有的人活在15年的熊市!
- 公用Foot和友情链接模块代码模板
- Python学习 Day31 DOM
- 7-1 计算π的值 (10分) java
- 怎么修改计算机密码界面的背景,操作方法:在Win10中输入密码时如何修改登录界面的背景图片(两种方法)...
- doom3 源代码评测 1