首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >业务对象/数据库访问层的体系结构

业务对象/数据库访问层的体系结构
EN

Stack Overflow用户
提问于 2008-09-23 03:30:57
回答 6查看 6K关注 0票数 7

出于各种原因,我们正在编写一个新的业务对象/数据存储库。这一层的要求之一是将业务规则的逻辑与实际的数据存储层分离。

有可能有多个数据存储层来实现对同一对象的访问--例如,实现大多数对象的主“数据库”存储源和实现用户对象的另一个"ldap“源。在这种情况下,用户可以选择来自LDAP源,可能具有稍微不同的功能(例如,不可能保存/更新用户对象),但否则应用程序将以相同的方式使用它。另一种数据存储类型可能是web服务或外部数据库。

我们有两种主要的方式来实现这一点,而我和一位同事在一个正确的基本层面上存在分歧。我想听听关于哪一个最好使用的建议。我将尽量保持我对每一个描述的中性,因为我在这里寻找一些客观的观点。

  • 业务对象是基类,数据存储对象继承业务对象。客户端代码处理数据存储对象。

在这种情况下,通用业务规则由每个数据存储对象继承,客户端代码直接使用的是数据存储对象。

这意味着客户端代码决定对给定对象使用哪种数据存储方法,因为它必须将实例显式声明为该类型的对象。客户端代码需要显式地知道它所使用的每种数据存储类型的连接信息。

如果数据存储层为给定对象实现了不同的功能,客户端代码在编译时就会显式地了解它,因为对象看起来不同。如果数据存储方法发生更改,则客户端代码必须是封装数据存储对象的updated.

  • Business对象。

在这种情况下,客户端应用程序直接使用业务对象。客户端应用程序将基本连接信息传递到业务层。由业务对象代码决定给定对象使用哪种数据存储方法。连接信息将是从配置文件中获取的数据块(客户端应用程序并不真正了解/关心它的详细信息),它可能是数据库的单个连接字符串,也可能是用于各种数据存储类型的多个连接字符串。其他数据存储连接类型也可以从另一个位置读取--例如,数据库中指定各种web服务URL的配置表。

这里的好处是,如果向现有对象添加了新的数据存储方法,则可以在运行时设置配置设置,以确定使用哪种方法,并且对客户端应用程序完全透明。如果给定对象的数据存储方法发生变化,则不需要修改客户端应用程序。

  • 业务对象是基类,数据源对象继承自业务对象。客户端代码主要处理基类。

这与第一种方法类似,但是客户端代码声明了基本业务对象类型的变量,业务对象上的Load()/Create()/etc静态方法返回适当的数据源类型对象。

该解决方案的体系结构类似于第一种方法,但主要区别在于由业务层而不是客户端代码来决定用于给定业务对象的数据存储对象。

我知道已有的ORM库提供了一些这种功能,但请不要考虑这些库(有可能使用这些ORM库之一实现数据存储层)--还请注意,我故意不告诉您这里使用的是哪种语言,只是它是强类型的。

我在这里寻找一些一般性的建议,关于哪种方法更适合使用(或者随意建议其他方法),以及为什么。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2008-09-23 03:36:56

我是否可以建议另一种选择,可能更好地分离:业务对象使用数据对象,数据对象实现存储对象。这应该保持业务对象中的业务规则,但不依赖于存储源或存储格式,同时允许数据对象支持所需的任何操作,包括动态地更改存储对象(例如,用于在线/脱机操作)。

这属于上面的第二类(业务对象封装数据存储对象),但将数据语义与存储机制更清楚地区分开来。

票数 11
EN

Stack Overflow用户

发布于 2008-09-23 03:50:27

您也可以有一个正面,以防止您的客户直接打电话给业务。此外,它还为您的业务创建了共同的入口点。

如前所述,除了DTO和外观之外,您的业务不应该暴露在任何东西上。

是。你的客户可以处理DTO。这是通过应用程序传递数据的理想方法。

票数 1
EN

Stack Overflow用户

发布于 2010-05-22 00:03:05

我通常最喜欢“业务对象封装数据对象/存储”。但是,在短时间内,您可能会发现数据对象和业务对象之间存在很高的冗余,这似乎不值得。如果选择ORM作为数据访问层(DAL)的基础,则尤其如此。但是,从长远来看,真正的回报是:应用生命周期。如图所示,“数据”来自一个或多个存储子系统(不限于RDBMS)并不少见,特别是随着云计算的出现,以及在分布式系统中的普遍情况。例如,您可能有来自Restful服务的一些数据,来自RDBMS的另一个块或对象,来自XML文件、LDAP等的另一个数据。有了这个实现,这就意味着非常好地封装来自业务的数据访问的重要性。也要注意通过c-tors和属性公开哪些依赖项(DI)。

尽管如此,我一直在玩的一种方法是将体系结构的“肉”放在业务控制器中。考虑到当前的数据-访问更多的是作为一种资源而不是传统的思想,然后控制器接受一个URI或其他形式的元数据,这些元数据可以用来知道它必须为业务对象管理哪些数据资源。然后,业务对象本身并不封装数据访问,而是由控制器封装。这使您的业务对象保持轻量级和特定性,并允许您的控制器提供优化、可组合、事务环境等等。请注意,您的控制器将“托管”您的业务对象集合,就像许多ORMs的控制器部分一样。

此外,还考虑业务规则管理。如果您仔细地斜视UML (或者像我这样在头脑中查看模型:D ),您会注意到您的业务规则模型实际上是另一个模型,有时甚至是持久的(例如,如果您使用的是业务规则引擎)。我会考虑让业务控制器也实际控制您的规则子系统,并让您的业务对象通过控制器引用规则。原因是,规则实现不可避免地需要执行查找和交叉检查,以确定有效性。通常,它可能需要水合的业务对象查找以及后端数据库查找。考虑检测重复的实体,例如,只有“新的”实体被水化。让您的规则由您的业务控制器来管理,那么您就可以完成您所需要的大多数事情,而不需要牺牲您的“域模型”中那个干净的抽象。

在伪码中:

代码语言:javascript
运行
复制
using(MyConcreteBusinessContext ctx = new MyConcreteBusinessContext("datares://model1?DataSource=myserver;Catalog=mydatabase;Trusted_Connection=True ruleres://someruleresource?type=StaticRules&handler=My.Org.Business.Model.RuleManager")) {

User user = ctx.GetUserById("SZE543");
user.IsLogonActive = false;
ctx.Save();
}

//a business object
class User : BusinessBase {
  public User(BusinessContext ctx) : base(ctx) {}

  public bool Validate() {
    IValidator v = ctx.GetValidator(this);
    return v.Validate();
  }
}

// a validator
class UserValidator : BaseValidator, IValidator {
 User userInstance;
 public UserValidator(User user) {
  userInstance = user;
 }

 public bool Validate() {
   // actual validation code here
   return true;
 }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/118955

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档