Mar*_*ers 8 c# service design-patterns domain-driven-design
我正在重构一个正在结束的项目的代码,最后我把很多业务逻辑放在服务类而不是域对象中.此时,大多数域对象仅是数据容器.我决定在服务对象中编写大部分业务逻辑,然后将所有内容重构为更好,更可重用和更易读的形状.这样我就可以决定应该将哪些代码放入域对象中,以及将哪些代码分解为自己的新对象,以及应该在服务类中保留哪些代码.所以我有一些代码:
public decimal CaculateBatchTotal(VendorApplicationBatch batch)
{
IList<VendorApplication> applications = AppRepo.GetByBatchId(batch.Id);
if (applications == null || applications.Count == 0)
throw new ArgumentException("There were no applications for this batch, that shouldn't be possible");
decimal total = 0m;
foreach (VendorApplication app in applications)
total += app.Amount;
return total;
}
Run Code Online (Sandbox Code Playgroud)
这段代码似乎是对域对象的一个很好的补充,因为它只有输入参数才是域对象本身.似乎是一些重构的完美候选人.但唯一的问题是该对象调用另一个对象的存储库.这让我想把它留在服务类中.
我的问题是这样的:
谢谢你的时间.
编辑注意:不能在这个上使用ORM,所以我不能使用延迟加载解决方案.
编辑注2:我不能改变构造函数来接受参数,因为将要使用反射(不是我的想法)实现域对象的方式.
编辑注3:我不相信批处理对象应该只能合计任何应用程序列表,看起来它应该只能处理该特定批处理中的应用程序.否则,将函数保留在服务类中对我来说更有意义.
我不是DDD的专家,但我记得伟大的杰里米·米勒的一篇文章为我回答了这个问题.您通常需要与域对象相关的逻辑 - 在这些对象中,但您的服务类将执行包含此逻辑的方法.这有助于我将特定于域的逻辑推入实体类,并使我的服务类不那么笨重(因为我发现自己在服务类中添加了很多逻辑,就像你提到的那样)
编辑:示例
我使用企业库进行简单验证,因此在实体类中我将设置如下属性:
[StringLengthValidator(1, 100)]
public string Username {
get { return mUsername; }
set { mUsername = value; }
}
Run Code Online (Sandbox Code Playgroud)
该实体继承自具有以下"IsValid"方法的基类,该方法将确保每个对象满足验证条件
public bool IsValid()
{
mResults = new ValidationResults();
Validate(mResults);
return mResults.IsValid();
}
[SelfValidation()]
public virtual void Validate(ValidationResults results)
{
if (!object.ReferenceEquals(this.GetType(), typeof(BusinessBase<T>))) {
Validator validator = ValidationFactory.CreateValidator(this.GetType());
results.AddAllResults(validator.Validate(this));
}
//before we return the bool value, if we have any validation results map them into the
//broken rules property so the parent class can display them to the end user
if (!results.IsValid()) {
mBrokenRules = new List<BrokenRule>();
foreach (Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResult result in results) {
mRule = new BrokenRule();
mRule.Message = result.Message;
mRule.PropertyName = result.Key.ToString();
mBrokenRules.Add(mRule);
}
}
}
Run Code Online (Sandbox Code Playgroud)
接下来我们需要在服务类保存方法中执行这个"IsValid"方法,如下所示:
public void SaveUser(User UserObject)
{
if (UserObject.IsValid()) {
mRepository.SaveUser(UserObject);
}
}
Run Code Online (Sandbox Code Playgroud)
更复杂的例子可能是银行账户.存款逻辑将存在于帐户对象内,但服务类将调用此方法.
您甚至不应该从域对象访问存储库.
您可以做的是让服务为域对象提供适当的信息,或者在域对象中具有由服务或构造函数设置的委托.
public DomainObject(delegate getApplicationsByBatchID)
{
...
}
Run Code Online (Sandbox Code Playgroud)