改变我们的BL设计 - 哪种模式最有用?

时间:2008-12-22 14:07:06

标签: architecture design-patterns

我正在重构我们的BI层,以使我们的代码更“松散耦合”,我有兴趣听听你们认为可能有意义的改进吗?

目前,我们的API类似于以下内容: -

// Fetch a collection of objects
ProductCollection prods = Product.GetProducts();

// Load an individual object, make change and save it back
Product p = new Product();
if(p.Load(productID))
{
    p.Name = "New Name";
    p.Save();
}

正如您所看到的,我们获取对象集合/加载单个对象和保存更改的方法都内置在“Model”类中。我们的每个Model类都继承自ObjectBase基类,其中包括数据库访问函数和更改跟踪,因此当有人通过属性更改值时,对象会自动标记为脏,并且会向任何订阅这些事件的对象(UI)触发通知。

我想要做的是使用“存储库模式”,以便我们可以从模型中抽象出数据库实现。但是,我一直在研究的大部分代码似乎都暗示“模型”类不应该包含任何智能,而应该只是数据的容器。相反,应该通过使用服务来应用逻辑。这是否意味着完成上述我需要做的事情

List<Product> prods = ProductService.GetProducts();

Product p = ProductService.GetSingleProduct(productID);
p.Name = "New Name";

ProductService.SaveProduct(p);

这似乎是一种更复杂的方式,并且使得在业务对象中封装功能变得更加困难。

有人可以解释为什么这是一种更好的做法,或者我误解了这些概念?

由于

詹姆斯

3 个答案:

答案 0 :(得分:6)

您当前的API是Active Record Pattern的实现。 当代码中使用的对象模型与数据库模型一对一匹配时,此模式可以正常工作。另一个优点是存在生成这些类的工具,包括持久性代码和数据库表。

您建议的替代方案是存储库模式。 正如您已经提到的,实现这一点有点复杂,但有几个优点。 由于您可以实现任何类型的ORM工具,因此您不仅限于一对一映射,而是可以实现更复杂的映射,其中对象模型可以与数据库模型不同。因此,您不必在数据库中强制使用对象模型,反之亦然。 然而,除了一对一之外,更复杂的映射不能生成并且需要一些

另一个优点是您可以更轻松地创建测试,因为您可以创建甚至不需要数据库的Mock存储库。

使用存储库模式,您还可以将模型与持久性逻辑分开。

在这两种情况下,都可以以泛型方式编写持久性方法,以便持久性代码是通用的,不需要知道需要持久化的特定对象。这对于Active Record Pattern来说是显而易见的,因为所有这些对象都实现了保存,删除,更新等。对于Repository Pattern,您还可以使用适用于任何对象的ORM工具,以便像这样的代码:

Repository.Save(ObjectOfAnyType);

ObjectOfAnyType可以是任何东西,只要ORM工具为对象类型定义/实现了一些映射。

所以你选择,你是否想要或需要这些优势,但代价是增加一点复杂性。或者Active Record Pattern的简单性是否足够。

我总是倾向于使用存储库模式,但有时使用Active Record Pattern,主要用于快速原型设计。

答案 1 :(得分:2)

我认为这里的主要问题是关注点分离:为什么您的业务对象应该如何关注它?为什么您的持久层应该关注业务对象的验证方式或强制执行业务逻辑?通过将两者分开,可以清楚地区分对象如何从业务角度进行操作以及如何从数据库中保存/检索它们。因此,您的业务对象变得不那么复杂(这很好),并且您可以在持久层中更轻松地利用共性来减少所需的代码量。

这对我真正有帮助的情况的一个例子是Model对象的子类化。当我在模型中构建Save逻辑时,我会从BI基类派生出相当多的逻辑,并实现一个虚拟方法来在Model类中实际保存对象。只要我的BI模型层次结构不变,这就可以正常工作。当想要继承模型时它会爆炸。那时我不得不重新实现很多用于保存的代码,因为我不能使用Base类代码而不重用直接父代码 - 这是我无法做到的。

我已经开始使用LINQ作为ORM,现在保存/检索逻辑在DataContext中,业务逻辑在每个业务实体的部分类中实现。这些类通过众所周知的接口实现验证(和其他业务逻辑)和负载检查。 DataContext使用该接口来执行所需的操作,以确保在持久化对象之前已满足业务规则。现在,我的Model类更加单一,更易于维护。 LINQ对子类化强制执行一些约束,但我可以通过构造接口来解决这个问题,或者,如果需要,可以重新编写我的数据库表以支持它们的子类约束。总而言之,我发现这是一个巨大的进步。

答案 2 :(得分:0)

@tvanfosson,@ Marco Tolk 感谢您的回复,非常有用。

我非常喜欢存储库模式带来的关注点分离。它确实在对象之间添加了更多的依赖关系,但我想使用像StructureMap这样的东西可以有效地将其作为一个障碍。

但是,我仍然不喜欢简化的“模型”概念。关于对象的逻辑(例如上例中的“product”)是否应该包含在对象本身中?

例如,如果我将产品对象绑定到编辑器,我希望它能够修改对象的属性,然后当用户点击保存时,让产品保持自身(可能通过存储库)。当业务对象“知道”足够坚持自己而不通过另一个服务进行管道传输时,在UI和业务对象之间建立服务是没有意义的。