手撸golang 结构型设计模式 代理模式
缘起
最近温习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采纳golang练习之
代理模式
代理模式(Proxy Pattern)指为其余对象提供一种代理,以管制对这个对象的拜访,属于结构型设计模式。
应用代理模式次要有两个目标:一是爱护指标对象,二是加强指标对象。
_
场景
- 某订单管理系统, 容许用户对订单进行增删改查
- 后减少日志需要, 要求对订单的Save和Delete操作, 记录操作日志
- 后再减少权限需要, 要求对订单的Save操作, 查看order.save权限; Delete操作, 查看order.delete权限
设计
- IUser: 定义用户信息及权限信息
- Order: 订单实体类
- IOrderService: 订单服务, 提供订单的增删改查办法
- tMockOrderService: 虚构订单服务, 提供对订单的增删改查的基本功能
- tLoggableOrderService: 依据日志需要, 新增的订单服务代理, 提供日志记录性能
- tSecureOrderService: 依据权限需要, 新增的订单服务代理, 提供权限查看性能
单元测试 - proxy_pattern_test.go
proxy_pattern_test.go顺次创立并调用了三种订单服务, 后两种以代理模式增加日志记录和权限查看性能.
package structural_patterns_testimport ( "learning/gooop/structural_patterns/proxy" "strings" "testing" "time")func Test_ProxyPattern(t *testing.T) { admin := proxy.NewMockUser(1, "管理员", strings.Split("order.load,order.save,order.delete", ",")) guest := proxy.NewMockUser(2, "张三", strings.Split("order.load", ",")) order := &proxy.Order{ ID: 1, OrderNo: "mock-order-1", CustomerID: 1, OrderDate: time.Now().Format("2006-01-02"), ReceiveAddress: "mock address", } os1 := proxy.NewMockOrderService() fnCallAndLog := func(fn func() error) { e := fn() if e != nil { t.Log(e) } } fnCallAndLog(func() error { return os1.Save(order, admin) }) fnCallAndLog(func() error { return os1.Delete(order.ID, admin) }) os2 := proxy.NewLoggableOrderService(os1) fnCallAndLog(func() error { return os2.Save(order, admin) }) fnCallAndLog(func() error { return os2.Delete(order.ID, admin) }) os3 := proxy.NewLoggableOrderService(proxy.NewSecureOrderService(os1)) fnCallAndLog(func() error { return os3.Save(order, admin) }) fnCallAndLog(func() error { return os3.Delete(order.ID, admin) }) fnCallAndLog(func() error { return os3.Save(order, guest) }) fnCallAndLog(func() error { return os3.Delete(order.ID, guest) })}
测试输入
$ go test -v proxy_pattern_test.go === RUN Test_ProxyPatternIOrderService.Save, user=管理员, order=&{1 mock-order-1 1 2021-02-01 mock address}, error=<nil>IOrderService.Delete, user=管理员, order.id=1, error=<nil>IOrderService.Save, user=管理员, order=&{1 mock-order-1 1 2021-02-01 mock address}, error=<nil>IOrderService.Delete, user=管理员, order.id=1, error=<nil>IOrderService.Save, user=张三, order=&{1 mock-order-1 1 2021-02-01 mock address}, error=permission denied proxy_pattern_test.go:26: permission deniedIOrderService.Delete, user=张三, order.id=1, error=permission denied proxy_pattern_test.go:26: permission denied--- PASS: Test_ProxyPattern (0.00s)PASSok command-line-arguments 0.002s
IUser.go
定义零碎用户接口, 用于订单服务上下文
package proxytype IUser interface { ID() int Name() string Allowed(perm string) bool}
tMockUser.go
tMockUser实现IUser接口, 封装运行时用户信息
package proxytype tMockUser struct { iID int sName string mPermissions map[string]bool}func NewMockUser(id int, name string, perms []string) IUser { it := &tMockUser{ id, name, make(map[string]bool, 16), } for _,k := range perms { it.mPermissions[k] = true } return it}func (me *tMockUser) ID() int { return me.iID}func (me *tMockUser) Name() string { return me.sName}func (me *tMockUser) Allowed(perm string) bool { if me.mPermissions == nil { return false } _,ok := me.mPermissions[perm] return ok}
Order.go
定义订单信息实体
package proxytype Order struct { ID int OrderNo string CustomerID int OrderDate string ReceiveAddress string}
IOrderService.go
订单服务接口
package proxytype IOrderService interface { Load(id int) (error, *Order) Save(order *Order, user IUser) error Delete(id int, user IUser) error}
tMockOrderService.go
虚构订单服务, 实现IOrderService接口, 提供订单的根本增删改查性能
package proxyimport ( "errors")type tMockOrderService struct { mItems map[int]*Order}func NewMockOrderService() IOrderService { return &tMockOrderService{ mItems: make(map[int]*Order, 16), }}func (me *tMockOrderService) Load(id int) (error, *Order) { //fmt.Printf("tMockOrderService.Load, id=%v\n", id) it, ok := me.mItems[id] if ok { return nil, it } else { return errors.New("no such order"), nil }}func (me *tMockOrderService) Save(it *Order, user IUser) error { me.mItems[it.ID] = it return nil}func (me *tMockOrderService) Delete(id int, user IUser) error { _,ok := me.mItems[id] if ok { delete(me.mItems, id) } else { return errors.New("no such order") } return nil}
tLoggableOrderService.go
订单服务代理, 以代理模式减少订单的Save和Delete日志
package proxyimport "fmt"type tLoggableOrderService struct { mOrderService IOrderService}func NewLoggableOrderService(service IOrderService) IOrderService { return &tLoggableOrderService{ mOrderService: service, }}func (me *tLoggableOrderService) Load(id int) (error, *Order) { return me.mOrderService.Load(id)}func (me *tLoggableOrderService) Save(it *Order, user IUser) error { e := me.mOrderService.Save(it, user) fmt.Printf("IOrderService.Save, user=%v, order=%v, error=%v\n", user.Name(), it, e) return e}func (me *tLoggableOrderService) Delete(id int, user IUser) error { e := me.mOrderService.Delete(id, user) fmt.Printf("IOrderService.Delete, user=%v, order.id=%v, error=%v\n", user.Name(), id, e) return e}
tSecureOrderService.go
订单服务代理, 以代理模式减少订单操作的权限查看性能
package proxyimport ( "errors")type tSecureOrderService struct { mOrderService IOrderService}var gErrorPermissionDenied = errors.New("permission denied")func NewSecureOrderService(service IOrderService) IOrderService { return &tSecureOrderService{ mOrderService: service, }}func (me *tSecureOrderService) Load(id int) (error, *Order) { return me.mOrderService.Load(id)}func (me *tSecureOrderService) Save(it *Order, user IUser) error { if !user.Allowed("order.save") { return gErrorPermissionDenied } return me.mOrderService.Save(it, user)}func (me *tSecureOrderService) Delete(id int, user IUser) error { if !user.Allowed("order.delete") { return gErrorPermissionDenied } return me.mOrderService.Delete(id, user)}
代理模式小结
动态代理vs动静代理
(1) 动态代理只能通过手动实现代理操作,如果被代理类减少了新的办法,则代理类须要同步减少,违反开闭准则。
(2)动静代理采纳在运行时动静生成代码的形式,勾销了对被代理类的扩大限度,遵循开闭准则。
代理模式的长处
(1)代理模式能将代理对象与实在被调用指标对象拆散。
(2)在肯定水平上升高了零碎的耦合性,扩展性好。
(3)能够起到爱护指标对象的作用。
(4)能够加强指标对象的性能。
代理模式的毛病
(1)代理模式会造成零碎设计中类的数量减少。
(2)在客户端和指标对象中减少一个代理对象,会导致解决申请的速度变慢。
(end)