设计问题——业务层方法应该有多原子?

发布于 2024-08-12 01:01:15 字数 1046 浏览 6 评论 0 原文

这个问题与技术无关,但我正在使用 C# 和 ASP.NET 并将其用于伪代码。哪种方法更好,为什么?

  1. 封装日志记录、事务和异常处理:

    protected void Page_Load(object sender, EventArgs e) {
     SomeBusinessClass.SomeBusinessMethod();
    }
    
    
    公共类 SomeBusinessClass {
      公共无效SomeBusinessMethod(){
        使用 (TransactionScope ts = new TransactionScope()) {
                    doStuff();
                    ts.Complete();
                }
                捕获(异常前){
                    LogError("保存订单时发生错误", ex);
                }
            }
        }
    }
    
  2. 将日志记录、事务和异常处理委托给调用者:

    protected void Page_Load(object sender, EventArgs e) {
        使用 (TransactionScope ts = new TransactionScope()) {
              尝试 {
                    SomeBusinessClass.SomeBusinessMethod();
                    ts.Complete();
              }
              捕获(异常前){
                    LogError("保存订单时发生错误", ex);
              }
         }
    }
    
    
    公共类 SomeBusinessClass {
      公共无效SomeBusinessMethod(){
          doStuff();
        }
    }
    

我担心通过在业务逻辑代码中引入对日志记录、事务等的依赖关系,我会使其不那么通用。另一方面,UI 代码看起来干净多了。我无法打电话。让我知道我还应该考虑哪些其他因素。

This issue is technology agnostic, but I am working with C# and ASP.NET and will use this for the pseudo code. Which is the better approach, and why?

  1. Encapsulate logging, transaction and exception handling:

    protected void Page_Load(object sender, EventArgs e) {
     SomeBusinessClass.SomeBusinessMethod();
    }
    
    
    public class SomeBusinessClass {
      public void SomeBusinessMethod() {
        using (TransactionScope ts = new TransactionScope()) {
                    doStuff();
                    ts.Complete();
                }
                catch (Exception ex) {
                    LogError("An error occured while saving the order", ex);
                }
            }
        }
    }
    
  2. Delegate logging, transaction and exception handling to the caller:

    protected void Page_Load(object sender, EventArgs e) {
        using (TransactionScope ts = new TransactionScope()) {
              try {
                    SomeBusinessClass.SomeBusinessMethod();
                    ts.Complete();
              }
              catch (Exception ex) {
                    LogError("An error occured while saving the order", ex);
              }
         }
    }
    
    
    public class SomeBusinessClass {
      public void SomeBusinessMethod() {
          doStuff();
        }
    }
    

I am concerned that by introducing dependencies on logging, transactions, etc in my business logic code, I make it less generic. On the other hand, the UI code looks so much cleaner. I can't make the call. Let me know what other factors I should consider.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

佞臣 2024-08-19 01:01:15

事务:业务层的核心关注点,因此它绝对应该处理这个问题(尽管您可以通过 工作单元实现)。

更新:我不再同意这部分内容。通常,控制器、演示者或其他顶级调用者是处理事务的最佳位置(例如 洋葱架构) - 在许多情况下,这就是定义工作逻辑单元的地方。

异常处理:在每一层根据需要使用 - 但仅在业务层使用当你实际上可以做一些事情(而不仅仅是记录它)。如果您的基础设施支持全局处理程序,请在 UI 层中使用全局处理程序。

日志记录:在任何需要的层中使用跟踪或信息日志记录,仅在顶层记录异常。

Transactions: a central concern of your business layer, so it should absolutely handle this (though you might centralize transaction handling via a unit of work implementation).

Update: I don't agree with this part any more. Often, the controller, presenter, or or another top-level caller is the best place to handle transactions (a la the the onion architecture) - in many cases, that's where the logical unit of work is defined.

Exception Handling: use as needed in every layer - but only use it in the business layer when you can actually do something about it (not just log it). Use a global handler in the UI layer if your infrastructure supports one.

Logging: use trace or informational logging in whatever layers need it, only log exceptions in the top layer.

白龙吟 2024-08-19 01:01:15

使用控制反转:

protected void Page_Load(object sender, EventArgs e) {
 new SomeBusinessClass(_logger, _dbcontext, _exceptionhandler).SomeBusinessMethod();
}

更好的方法是

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod();
}

通过 IoC 容器将 _mybusiness 类以及填充的 _logger、_dbcontext 和 _exceptionhandler 传递到您的页面。如果您需要手动创建 _exceptionhandler,例如“new RedirectExceptionHandler(this)”,那么

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod(new RedirectExceptionHandler(this));
}

现在它实际上归结为您的具体设计决策。不过,由于我使用 MVC,所以不知道如何在 ASP.NET 中执行 IoC。

另一种选择是使用面向方面的编程来捕获异常并进行日志记录。另一种选择(可在 www.sharparchitecture.net 中找到)是使用方法上的 [Transaction] 属性以声明方式处理事务。

Use Inversion of Control:

protected void Page_Load(object sender, EventArgs e) {
 new SomeBusinessClass(_logger, _dbcontext, _exceptionhandler).SomeBusinessMethod();
}

A better one would be

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod();
}

where _mybusiness class is passed to your page via IoC container, along with populated _logger, _dbcontext, and _exceptionhandler. If you need to create _exceptionhandler manually, for example "new RedirectExceptionHandler(this)", then

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod(new RedirectExceptionHandler(this));
}

Now it really boils down to your specific design decisions. Don't know how to do IoC in ASP.NET, though, since I use MVC.

Another option is to use Aspect Oriented Programming to catch exceptions and do logging. Yet another option (available in www.sharparchitecture.net) is to handle transactions declaratively using [Transaction] attributes on method.

伪装你 2024-08-19 01:01:15

任何让 UI 更薄的东西都会让你的生活更轻松。

Anything that makes the UI thinner will make your life easier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文