douyun7718 2018-09-12 14:41
浏览 112
已采纳

Golang中的工厂功能[关闭]

I have a service object similar to the one shown below which is exposed through HTTP:

type ComputeService struct {

}

func (svc ComputeService) Compute(userType string, data Data) (Result, error) {
   // rate limit based on userType (both check and increment counter)
   // if not rate limited, compute and return result
}

Now, as you can see rate-limiting needs to be done based on userType. Implementation of rate limiter itself changes according to userType. I am thinking of 2 approaches of resolving the rate limiter using userType.

// First approach: for each request new ComputeService object is
// created after resolving RateLimiter using userType in the handler
// itself
type ComputeService struct {
    RateLimiter RateLimiter
}

// Second approach: ComputeService object is initialized during startup
// and only RateLimiter is resolved with every Compute() call by calling
// the provider function
type ComputeService struct {
    RateLimiterProvider func(userType string) RateLimiter
}

Both are testable. Which one would be preferable ? I'm leaning towards the 2nd approach since using it would mean that the handler will be purely read request, delegate to service, write out the response whereas in 1st approach, handler would contain additional step of resolving the rate limiter implementation.

  • 写回答

1条回答 默认 最新

  • doupishan3309 2018-09-12 15:13
    关注

    If you are using a DI system like Dargo you can use its Provider injection to dynamically choose the implementation at runtime.

    In that case your services would look something like the following:

    import "github.com/jwells131313/dargo/ioc"
    
    type RateLimiter interface {
    }
    
    type UserType1RateLimiter struct {
    }
    
    type UserType2RateLimiter struct {
    }
    
    type ComputeService struct {
        RateLimiterProvider ioc.Provider `inject:"RateLimiter"`
    }
    
    func (svc ComputeService) Compute(userType string, data Data) (Result, error) {
        // rate limit based on userType (both check and increment counter)
        // if not rate limited, compute and return result
        raw, err := svc.RateLimiterProvider.QualifiedBy(userType).Get()
        if err != nil {
            return nil, err
        }
    
        limiter := raw.(RateLimiter)
        //...
    }  
    

    This is how you would bind these into the ServiceLocator:

    func initializer() {
        serviceLocator, _ = ioc.CreateAndBind("ExampleLocator", func(binder ioc.Binder) error {
            binder.Bind("RateLimiter", UserType1RateLimiter{}).QualifiedBy("UserType1")
            binder.Bind("RateLimiter", UserType2RateLimiter{}).QualifiedBy("UserType2")
            binder.Bind("ComputeService", ComputeService{})
            return nil
        })
    }
    

    This only applies when you are using something like Dargo, but it still might be useful in your case.

    If you are not using Dargo it seems to me to be a matter of opinion, although I personally would choose the second approach

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?
  • ¥15 matlab(相关搜索:紧聚焦)
  • ¥15 基于51单片机的厨房煤气泄露检测报警系统设计
  • ¥15 路易威登官网 里边的参数逆向
  • ¥15 Arduino无法同时连接多个hx711模块,如何解决?
  • ¥50 需求一个up主付费课程