关于golang:手撸golang-结构型设计模式-代理模式

手撸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_test

import (
    "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_ProxyPattern
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=<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 denied
IOrderService.Delete, user=张三, order.id=1, error=permission denied
    proxy_pattern_test.go:26: permission denied
--- PASS: Test_ProxyPattern (0.00s)
PASS
ok      command-line-arguments  0.002s

IUser.go

定义零碎用户接口, 用于订单服务上下文

package proxy

type IUser interface {
    ID() int
    Name() string
    Allowed(perm string) bool
}

tMockUser.go

tMockUser实现IUser接口, 封装运行时用户信息

package proxy

type 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 proxy

type Order struct {
    ID int
    OrderNo string
    CustomerID int
    OrderDate string
    ReceiveAddress string
}

IOrderService.go

订单服务接口

package proxy

type IOrderService interface {
    Load(id int) (error, *Order)
    Save(order *Order, user IUser) error
    Delete(id int, user IUser) error
}

tMockOrderService.go

虚构订单服务, 实现IOrderService接口, 提供订单的根本增删改查性能

package proxy

import (
    "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 proxy

import "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 proxy

import (
    "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)

评论

发表回复

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

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理