情况
今天晚上早些时候,我回答了关于StackOverflow的问题。
问题:
现有对象的编辑应该在存储层还是在服务中进行?
例如,如果我有一个负债的用户。我想改变他的债务。我应该通过获取对象,对其进行编辑并保存来在UserRepository或服务(例如BuyingService)中进行操作吗?
我的答案:
您应该将将一个对象变异为相同的对象,并使用存储库来检索该对象。
情况示例:
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
我收到的评论:
业务逻辑实际上应该在服务中。不在模型中。
互联网怎么说?
因此,这使我开始寻找,因为我从未真正(有意识地)使用过服务层。我开始阅读“服务层”模式和“工作单位”模式,但到目前为止,我还不能说我确信必须使用服务层。
例如,Martin Fowler的这篇关于贫血域模型的反模式的文章:
在领域空间中,有许多对象以名词命名,这些对象与真实领域模型所具有的丰富关系和结构相关联。当您观察行为时就会发现问题所在,并且您意识到这些对象几乎没有任何行为,这使它们仅比一堆吸气剂和塞脂剂小得多。确实,这些模型经常带有设计规则,这些规则说您不要在域对象中放置任何域逻辑。而是有一组服务对象捕获了所有域逻辑。这些服务位于域模型之上,并使用域模型存储数据。
(...)域对象中应该包含的逻辑是域逻辑-验证,计算,业务规则-随便您如何称呼它。
在我看来,这恰好是这种情况:我提倡通过在类内部引入可做到这一点的方法来操纵对象的数据。但是我意识到这应该是给定的任何一种方式,并且可能与如何调用这些方法(使用存储库)有更多关系。
我还觉得在那篇文章中(见下文),服务层比实际的工作量大的层更被视为将工作委托给基础模型的立面。
应用程序层[他的服务层名称]:定义软件应该执行的工作,并指导可表达的领域对象解决问题。该层负责的任务对业务有意义或与其他系统的应用程序层交互所必需。该层保持薄。它不包含业务规则或知识,仅协调任务并将工作委托给下一层的域对象协作。它没有反映业务情况的状态,但是可以具有反映用户或程序的任务进度的状态。
在这里加强:
服务接口。服务公开了将所有入站消息发送到的服务接口。您可以将服务接口视为外观,向潜在的使用者公开应用程序中实现的业务逻辑(通常是业务层中的逻辑)。
而在这里:
服务层应该没有任何应用程序或业务逻辑,并且应该主要关注一些问题。它应该包装业务层调用,以客户端可以理解的通用语言翻译域,并处理服务器与请求客户端之间的通信介质。
服务层应包含具有方法的类,这些方法是具有属于同一事务的动作的工作单元。
或我已经链接的问题的第二个答案:
在某个时候,您的应用程序将需要一些业务逻辑。另外,您可能希望验证输入,以确保没有任何有害或不良要求。此逻辑属于您的服务层。
“解”?
按照此答案中的准则,我提出了以下使用服务层的方法:
class UserController : Controller {
private UserService _userService;
public UserController(UserService userService){
_userService = userService;
}
public ActionResult MakeHimPay(string username, int amount) {
_userService.MakeHimPay(username, amount);
return RedirectToAction("ShowUserOverview");
}
public ActionResult ShowUserOverview() {
return View();
}
}
class UserService {
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository) {
_userRepository = userRepository;
}
public void MakeHimPay(username, amount) {
_userRepository.GetUserByName(username).makePayment(amount);
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
结论
总的来说,这里的变化不大:控制器中的代码已移至服务层(这是一件好事,因此这种方法有一个好处)。但是,这似乎与我的原始答案没有任何关系。
我意识到设计模式是指导原则,而不是一成不变的规则,只要有可能就予以实施。但是我还没有找到关于服务层以及如何考虑的明确解释。
这是一种简单地从控制器中提取逻辑并将其放入服务中的方法吗?
是否应该在控制器和域之间形成合同?
域和服务层之间应该有一层吗?
最后但并非最不重要的一点:遵循原始评论
业务逻辑实际上应该在服务中。不在模型中。
这个对吗?
- 如何将业务逻辑引入服务而不是模型中?