如何防止业务逻辑重复?

发布于 2024-08-09 03:14:59 字数 981 浏览 2 评论 0原文

好的。这是我的简化场景。我们有一个为许多客户处理订单的系统。我们希望员工用户能够查看所有订单,而我们希望客户用户只能查看与其相关的订单。

当尝试查看特定记录时,我们在 OrderSecurity 类中使​​用以下函数:

Public Function CanViewOrder(order)
    If currentUser.MemberOfStaff() Then
        CanViewOrder = True
    Else
        CanViewOrder = (order.ClientId = currentUser.ClientId)
    End If
End Function

当我们想要向用户显示订单列表时,我们可以使用 OrderService 类中定义的以下函数

Public Function GetOrders()
    If currentUser.MemberOfStaff() Then
        GetOrders = GetAllOrders()
    Else
        GetOrders = GetAllOrdersForClient(currentUser.ClientId)
    End If
End Function

这对于上述情况是可以的,但是随着规则变得更加复杂,这种做法并不能很好地维持下去。例如,我们添加另一种用户类型,该用户类型代表不太受信任的员工,他只能查看来自客户子集的订单。然后,我们必须向 CanViewOrder 和 GetOrders 函数(以及可能在数据访问类中)添加逻辑,在我看来,这违反了 DRY 原则。

所以,我的问题是:我在这里错过了一个技巧 - 有什么方法可以将业务逻辑结合起来,以允许在这两个功能都可以使用的一个地方查看订单吗?

还是我担心太多了,应该继续并在两个地方建立逻辑?

(在这个特定的应用程序中,我使用 ASP Classic - 不是讨厌玩家,而是讨厌游戏 - 但我对你如何用任何语言解决这个问题感兴趣)

OK. So here's my simplified scenario. We have a system which handles orders for a number of clients. We want staff users to be able to view all orders and we want client user to only be able to view orders which relate to them.

When attempting to view a particular record we make use of the following function in our OrderSecurity class:

Public Function CanViewOrder(order)
    If currentUser.MemberOfStaff() Then
        CanViewOrder = True
    Else
        CanViewOrder = (order.ClientId = currentUser.ClientId)
    End If
End Function

At points when we want to display a list of orders to a user we can the following function defined in a OrderService class

Public Function GetOrders()
    If currentUser.MemberOfStaff() Then
        GetOrders = GetAllOrders()
    Else
        GetOrders = GetAllOrdersForClient(currentUser.ClientId)
    End If
End Function

This is OK for the above but doesn't hold up well as the rules get more complicated. Say, for example, we add another user type which represents a less trusted staff member who can only view orders from a sub-set of clients. We'd then have to add logic to the CanViewOrder and GetOrders functions (and potentially in the data access classes) which in my mind violates the DRY principle.

So, my question is: Am I missing a trick here - is there some way I can combine the business logic for permission to view orders in one place which both of these functions can use?

Or am I worrying too much and should just get on and have the logic in two places?

(In this particular application I'm using ASP Classic - don't hate the player, hate the game - but I'd be interested in how you solve this problem in any language)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

写给空气的情书 2024-08-16 03:14:59

IMO,你不会在这里重复自己。 CanViewOrder 中的业务逻辑与 GetOrders 中的业务逻辑不同。确实,表面上有相似之处,但从理论上讲,这两个规则可能会以不同的方式发展。

IMO you are not repeating yourself here. The business logic in CanViewOrder is not the same as the business logic in GetOrders. There is a superficial resemblance, it's true, but the two rules could theoretically evolve differently.

空‖城人不在 2024-08-16 03:14:59

您可以集中访问策略并使其更加通用(可能以牺牲效率为代价),方法是将其保留在像您这样的谓词中,只是稍微概括一下以同时考虑主语(用户)和宾语(顺序):

Public Function CanView(user, order)
    (magic)
End Function

然后避免重复通过将 GetOrders(user) 实现为过滤器,对订单集应用 CanView(user, order) 来设置您的访问策略。

走这条路线后,您也可以一劳永逸地定义其他“查询”,其方式独立于策略及其变化方式。例如: GetUsersWhoCanView(order), CanViewSameOrders(user1, user2), CanAnybodyView(order),...

对于一个简单且相对静态的策略只有少数功能依赖它,“直接方法”,有据可查,可以为您提供最佳效率和最少的麻烦。如果您的策略可能变得复杂或可能经常更改或最终可能在未来被许多其他功能使用,那么使用我上面概述的模块化方法可以避免产生技术债务。

You could concentrate the access policy and make it more general (probably at the expense of efficiency) by keeping it in a predicate like you have, just slightly generalised to take both subject (user) and object (order) into account:

Public Function CanView(user, order)
    (magic)
End Function

Then avoid repeating your access policy by implementing GetOrders(user) as a filter applying CanView(user, order) over the set of orders.

Having gone this route you can define other "queries", too, once and for all, in a way independent of the policy and how it may change. For example: GetUsersWhoCanView(order), CanViewSameOrders(user1, user2), CanAnybodyView(order),...

For a simple and relatively static policy with only a small number of functions relying on it, the "direct approach", well documented, gives you the best efficiency and least headache. If your policy could become complex or could change often or could end up being used by many other functions in the future, using the modular approach I outlined above avoids incurring technical debt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文