由于种种原因,我们正在编写一个新的业务对象/数据存储库。 一的该层的要求,是的业务规则逻辑,和实际的数据存储层中分离出来。
它可以具有实现访问同一对象的多个数据存储层 - 例如,一个实现大多数对象一主“数据库”的数据存储源,和实现用户对象另一个“LDAP”源。 在这种情况下,用户可任选地具有略微不同的功能(例如,无法保存/更新用户对象)来从LDAP源,也许,但是否则就由应用程序使用的方式相同。 另一个数据存储类型可能是一个Web服务,或外部数据库。
还有我们正在实施这一主要有两种方式,我和一个同事不同意一个基本的水平,这是正确的。 我想一些建议,哪一个是最好的使用。 我会尽力保持各个尽可能中性的我的描述,因为我在寻找一些客观的观点在这里。
业务对象是基类,以及数据存储对象继承业务对象。 客户端代码与数据存储对象的交易。
在此情况下,常见的业务规则是由每个数据存储对象继承,并且它是被直接使用的客户端代码的数据存储对象。
这具有客户代码确定使用哪个数据存储方法对于给定的对象,因为它有明确声明的实例,以该类型的对象的含义。 客户端代码需要明确地知道它是用每个数据存储类型的连接信息。
如果数据存储层给定对象实现不同的功能,客户端代码明确地在编译时知道它因为对象看起来不一样。 如果数据存储方法改变时,客户端代码必须被更新。
业务对象封装数据的存储对象。
在这种情况下,业务对象直接使用客户端应用程序。 客户端应用程序沿着底座连接信息,业务层传递。 关于哪些数据存储方法的给定对象使用由业务对象代码所做的决定。 连接信息是从配置文件取(客户端应用程序并不真正了解它的细节/保健)的数据块,这可能是一个数据库,或用于各种数据存储类型几件连接字符串一个连接字符串。 其他数据存储的连接类型也可以从另一个地方读 - 例如,在指定的URL各种网络服务的数据库的配置表。
这里的好处是,如果一个新的数据存储方法被添加到现有的对象,配置设置可以在运行时设置为确定要使用的方法,并且它是完全透明的客户端应用程序。 客户机应用程序不需要的,如果数据存储方法进行修改给定对象的变化。
业务对象是基类,数据源对象从业务对象继承。 客户端代码基类主要交易。
这类似于第一种方法,但客户端代码声明了基础业务对象类型的变量,和加载()/创建()/等上的业务对象的静态方法返回适当的数据源类型对象。
这种解决方案的结构类似于第一种方法,但主要区别是关于使用哪个数据存储对象对于给定的业务对象是由业务层,而不是客户端代码的决定。
我知道,一些提供这种功能,但请那些打折,现在也有已经存在的ORM库(有一个数据存储层与这些ORM库的一个实现的可能性) - 也注意到我故意不告诉你什么语言正在这里使用的,比它是强类型等。
我在找一些一般建议这里哪一种方法更好地使用(或随时提出别的东西),以及为什么。
也许我建议另一种选择,可能有更好的去耦:业务对象使用的数据对象和数据对象实现的存储对象。 这应该保持在业务对象,但没有存储源或格式上的任何依赖业务规则,同时允许数据对象以支持所需的任何操作,包括动态改变存储对象(如在线/离线操作)
此落入上述第二类(业务对象封装的数据的存储对象),而是从存储机制更清楚地分离的数据的语义
您也可以有一个门面,从你的客户保持直接调用业务。 此外,它创建的公共入口点,您的业务。
至于说,你的业务不应该暴露于任何东西,但你的DTO和门面。
是。 您的客户端可以处理的DTO。 这是通过应用程序来传递数据的理想方式。
我一般喜欢“业务对象封装数据对象/存储”最好的。 然而,在短期你可能会发现你的数据对象和业务对象的高冗余,可能看上去很不划算。 如果你选择的ORM为您的数据访问层(DAL)的基础上,尤其如此。 但是,从长远来看是真正还清是:应用程序生命周期。 如图所示,它是不寻常的“数据”,以来自一个或更多个存储子系统(不限于RDBMS),尤其是与云计算的出现,并且如通常在分布式系统中的情况。 例如,你可能有来自RESTful服务,从XML文件,LDAP另一块或物体从一个RDBMS,另一个,等等一些数据。 有了这个认识,这意味着从业务数据访问非常良好的封装的重要性。 小心哪些依赖您通过C-职责范围和属性公开(DI),太。
也就是说,这种方法我一直在玩弄就是把建筑的“肉”在商业控制器。 更由于比传统思想资源的当代数据访问思考,控制器再接受一个URI或可用于了解数据资源就必须管理业务对象元数据的其他形式。 然后,业务对象本身不封装数据的访问; 而控制器一样。 这样可以使你的业务对象轻便的并允许在你的控制器,提供优化的,可组合,交易氛围,等等。 请注意,您的控制器将接着“托管”业务对象的集合,就像许多的ORM的控制器一块做。
此外,还要考虑业务规则管理。 如果您在您的UML眯着眼睛很难(或者在你的脑袋模型像我这样做:d),你会发现,你的业务规则模型实际上是另一种模式,有时甚至是永久性的(如果你使用的是商业规则引擎,例如) 。 我会考虑让业务控制器还实际控制你的规则子系统也让你的业务对象通过控制器引用的规则。 究其原因是因为,不可避免的是,规则的实施往往需要进行查找和交叉检查,以确定有效性。 通常情况下,它可能需要两个水合业务对象的查找,以及后端数据库查找。 考虑检测重复的实体,例如,其中只有“新”一水合。 离开你的规则,由业务控制器来管理,你可以再做任何东西,你需要在不牺牲,在你干净的抽象“的域模型。”
在伪代码:
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;
}
}
客户不应该直接处理存储对象。 他们可以对付DTO的直接,但有什么逻辑存储未裹在你的业务对象的任何对象不应该通过直接在客户端调用。
好了,我在这里的同事格雷格提及。
格雷格说明我们一直在考虑,丝丝入扣的替代品。 我只是想一些额外的考虑添加的情况说明。
客户代码可以是不知道关于数据存储,其中的业务对象存储,但也可以无论是在情况下,当只存在一个数据存储,或存在用于相同的业务对象类型(用户存储在本地数据库中外部LDAP),但多个datastorages客户端不创建这些业务对象。 在系统的分析而言,这意味着应该是没有用例,其中相同类型的对象的两个datastorages的存在可以影响使用的情况下流动。
只要在储存产生不同的数据创建区分对象的需要,客户端组件必须意识到关于其Universe数据存储器的多重性,这将不可避免地成为负责其数据存储的决定,将创建对象的瞬间使用(而且,我认为,从数据存储对象装载)。 业务层可以假装它是使这一决策,但决策的算法将根据类型和从客户端组件传来的信息内容,使客户有效的决定负责。
这种责任可以以许多方式来实现的:它可以是特定类型的每个数据存储的连接对象; 可以segregared方法调用创建新实例BO等
问候,
迈克尔
里昂证券已经存在很长一段时间。 但是我喜欢在Eric Evans的书讨论的方法http://dddcommunity.org/