将业务(服务)层依赖于用户会话是不好的设计?

Ras*_*nke 9 java architecture ejb

在常见的MVC设计应用程序中,使服务层依赖于用户会话是一个坏主意吗?假设有一种服务方法从数据库中提取一些对象,并且您希望根据初始化调用的人返回不同的结果 - 例如,管理员可能获得10行对象,而普通用户可能只获得7行因为最后3个是"仅限管理员"的对象.解决这个问题的几种方法是:

  • 引入一个包含主叫用户的新方法参数.在许多方法中必须抛出用户参数的依赖性较小但很麻烦.
  • 为不同的用户角色制作不同的方法(具有多个结果).同样依赖于依赖性但很多方法基本上做同样的事情,这增加了代码重复的风险.
  • 让方法从存储当前用户会话的静态上下文中的ThreadLocal变量读取.在每个请求之前设置此变量.

最近,我开始越来越多地使用最后一种方法,因为它提供了一个干净的界面,并且使用起来非常实用.过滤器确保当前线程始终具有用户设置.这是不好的设计吗?我相信有些人可以将其视为从服务层到Web层的依赖,尽管我个人认为它们非常不相关.最大的后果是方法行为会因另一个类的状态而有所不同,这可能既是坏事也是好事.

你对此有何看法?如果这是一个糟糕的解决方案,那么什么会更强大?

mik*_*era 5

我强烈建议使用aginst ThreadLocal风格的方法 - 它看起来像是一个"全局变量"设计气味太多了.这有很多问题,最值得注意的是:

  • 当你在测试之前设置越来越多的隐式全局状态时,你的代码变得越来越难以测试
  • 无法清楚地看到某段代码正在使用哪些参数.这对于维护者来说可能非常混乱,或者如果您在几个月后回到代码中.
  • 如果您将工作交给不同的线程,它可能会导致非常讨厌的错误/复杂性.您已经有效地使代码执行依赖于它运行在哪个线程上......可能出现什么问题?:-)
  • 您正在创建循环依赖项(服务层< - >用户界面层).从来没有一个好主意,你应该尝试保持依赖只流一种方式(几乎总是用户界面层 - >服务层)

在另外两种方法之间,我认为"这取决于":

  • 如果用户本质上是数据模型的一部分(例如,您有一个社交图数据库),那么将用户作为参数传递似乎很自然.
  • 如果用户数据仅用于身份验证等前端内容,那么我倾向于最小化对特定用户详细信息的依赖性,而是为不同角色创建不同的方法(或者等效地添加"角色"参数).

另一种选择是将"上下文"对象传递到包含一组相关会话数据(即不仅仅是用户名)的服务层.如果您想最小化参数膨胀,这可能是有意义的.请注意它变成了一种"绕过"良好分层原则的方法.如果它只是"数据"那么它可能没什么问题,但是一旦人们开始在上下文中传递回调对象/ UI组件,那么你可能会走向有点混乱....