第三方类型Person
。它只是公开了Subscriptions
集合,这是一个人订阅的邮件列表列表:
public class Person
{
public Person(int id)
public IList<int> Subscriptions {get;set;}
}
(它的mutable,没有任何验证,每个人都可以清理它,但那是第三方API。)
我需要放置某种订阅业务逻辑并寻找合适的位置(订阅可能有一些验证规则,它们可能会根据某些条件自动添加或删除等)。我可以在这里看到两个选项:
选项1:
这可能是我的解决方案中的新Recipient
类型,其中所有业务逻辑都封装在Subscribe
和Unsubscribe
方法中:
public class Recipient
{
public Recipient(Person person) { ... }
public void SubscribeTo(int mailingListId) { ... }
public void UnsubscribeFrom(int mailingListId) { ... }
}
选项2:
同样的事情,但转变为PersonExtensions
类:
public static class PersonExtensions
{
public static void SubscribeTo(this Person person, int mailingListId) { ... }
public static void UnsubscribeFrom(this Person person, int mailingListId) { ... }
}
静态扩展方法可能会阻止我创建大量Recepient
实例,但看起来不适合放置BL。这样做有什么缺点吗?
答案 0 :(得分:1)
在我看来,你绝对应该选择选项1。扩展方法不是用于处理业务逻辑;这应该总是发生在一个班级。我认为您将Person
课程的关注点与Recipient
人的关注点分开是正确的。如果您正在考虑SOLID design principles,那么您肯定在选项1的正确轨道上。
S 单一责任,IE一类应该只有一个责任(一个“改变的理由”)。与您使用扩展方法代替类的问题没有密切关系,但它可以通过将人与收件人分开来证明您处于正确的轨道上。如果您的收件人逻辑发生了变化,您不必修改使用人员但不关心收件人逻辑的每一段代码。
O 笔/已关闭 - 打开以进行扩展,关闭以进行修改。 (不要让使用“扩展”这个词让你想到扩展方法。)你应该总是能够添加你的(最好是抽象的)父类的扩展(子类)。像多态这样的面向对象编程的基本原则在这里发挥作用,如果选项2可以实现则没有。
L iskov替换dove-tails很好地使用开放/封闭原则,因为它允许您替换代码中的类,这些类需要父类的实例和新的“扩展”子实例-class。
如果将所有逻辑放在一个带扩展方法的静态类中,这一切都不可能。
答案 1 :(得分:1)
我不同意所选答案。 业务规则经常更改,并将它们添加到域实体中,将易变的逻辑紧密耦合到可能几乎不变的对象。如果明天由于业务条件变化而需要添加更多规则或更改规则,该怎么办?还是如果相同的规则对不同的地理区域有不同的适用呢?您需要一次又一次地干预您的对象,添加或删除方法,从而增加复杂性,从而增加冗长性。如今在大多数行业中,这都是极有可能的情况。而且,这些方法可能是公开的。因此,除非您围绕它们构建复杂的应用程序逻辑,否则任何人都可能以错误的方式使用它们。
解决方案是将业务规则与域对象分离,委派第三个对象来决定如何组合它们以及如何(以及何时)应用它们。这就是业务规则引擎出现的地方。它们使您可以创建用于封装任何域实体的业务规则的类,将它们添加到规则存储库中,并根据需要触发它们(因此,您确实必须知道自己在做什么)。另一个优点是,您可以使域实体保持简洁明了,不受业务逻辑的冗长和复杂性的影响。
更高级的引擎使用复杂的算法(例如rete one),能够自己(大多数时候)弄清楚应该应用规则并支持依赖注入的确切顺序。我个人使用NRules:这是一个开放源代码,可用于企业的规则引擎,快速可靠,建立在rete算法之上。
https://github.com/NRules/NRules
尝试一下,让我知道;)