package cache
import (
"context"
"crypto/md5"
"encoding/json"
"fmt"
"reflect"
"time"
)
// 缓存装饰器
type CacheDecorator struct {
cache Cache
prefix string
ttl time.Duration
}
// 创建缓存装饰器
func NewCacheDecorator(cache Cache, prefix string, ttl time.Duration) *CacheDecorator {
return &CacheDecorator{
cache: cache,
prefix: prefix,
ttl: ttl,
}
}
// 缓存函数调用结果
func (cd *CacheDecorator) CacheFunc(ctx context.Context, fn interface{}, args ...interface{}) ([]reflect.Value, error) {
// 生成缓存键
key, err := cd.generateKey(fn, args...)
if err != nil {
return nil, err
}
// 尝试从缓存获取
if cached, err := cd.cache.Get(ctx, key); err == nil {
var result []reflect.Value
if err := json.Unmarshal(cached.([]byte), &result); err == nil {
return result, nil
}
}
// 执行函数
fnValue := reflect.ValueOf(fn)
if fnValue.Kind() != reflect.Func {
return nil, fmt.Errorf("not a function")
}
argValues := make([]reflect.Value, len(args))
for i, arg := range args {
argValues[i] = reflect.ValueOf(arg)
}
results := fnValue.Call(argValues)
// 缓存结果
if data, err := json.Marshal(results); err == nil {
cd.cache.Set(ctx, key, data, cd.ttl)
}
return results, nil
}
// 生成缓存键
func (cd *CacheDecorator) generateKey(fn interface{}, args ...interface{}) (string, error) {
fnType := reflect.TypeOf(fn)
keyData := struct {
Prefix string `json:"prefix"`
FuncName string `json:"func_name"`
Args interface{} `json:"args"`
}{
Prefix: cd.prefix,
FuncName: fnType.String(),
Args: args,
}
data, err := json.Marshal(keyData)
if err != nil {
return "", err
}
hash := md5.Sum(data)
return fmt.Sprintf("%s:%x", cd.prefix, hash), nil
}
// 缓存方法装饰器
type MethodCacheDecorator struct {
*CacheDecorator
}
// 创建方法缓存装饰器
func NewMethodCacheDecorator(cache Cache, prefix string, ttl time.Duration) *MethodCacheDecorator {
return &MethodCacheDecorator{
CacheDecorator: NewCacheDecorator(cache, prefix, ttl),
}
}
// 缓存方法调用
func (mcd *MethodCacheDecorator) CacheMethod(ctx context.Context, obj interface{}, methodName string, args ...interface{}) ([]reflect.Value, error) {
objValue := reflect.ValueOf(obj)
method := objValue.MethodByName(methodName)
if !method.IsValid() {
return nil, fmt.Errorf("method %s not found", methodName)
}
// 生成包含对象信息的缓存键
key, err := mcd.generateMethodKey(obj, methodName, args...)
if err != nil {
return nil, err
}
// 尝试从缓存获取
if cached, err := mcd.cache.Get(ctx, key); err == nil {
var result []reflect.Value
if err := json.Unmarshal(cached.([]byte), &result); err == nil {
return result, nil
}
}
// 执行方法
argValues := make([]reflect.Value, len(args))
for i, arg := range args {
argValues[i] = reflect.ValueOf(arg)
}
results := method.Call(argValues)
// 缓存结果
if data, err := json.Marshal(results); err == nil {
mcd.cache.Set(ctx, key, data, mcd.ttl)
}
return results, nil
}
// 生成方法缓存键
func (mcd *MethodCacheDecorator) generateMethodKey(obj interface{}, methodName string, args ...interface{}) (string, error) {
objType := reflect.TypeOf(obj)
keyData := struct {
Prefix string `json:"prefix"`
ObjectType string `json:"object_type"`
MethodName string `json:"method_name"`
Args interface{} `json:"args"`
}{
Prefix: mcd.prefix,
ObjectType: objType.String(),
MethodName: methodName,
Args: args,
}
data, err := json.Marshal(keyData)
if err != nil {
return "", err
}
hash := md5.Sum(data)
return fmt.Sprintf("%s:%s:%s:%x", mcd.prefix, objType.Name(), methodName, hash), nil
}