带有序言和尾声的设计模式

本文关键字:设计模式 | 更新日期: 2023-09-27 18:36:56

我正在寻找可以实现一些prolog代码然后epilog代码的设计模式。让我解释一下:

我有一个函数(很多)最能做同样的事情:

这是presudo代码,但实际上是用C#4.5编写

public IDatabaseError GetUserByName(string Name)
{
  try
  {
      //Initialize session to database
  }
  catch (Exception)
  {
     // return error with description for this step
  }
  try
  {
       // Try to create 'transaction' object
  }
  catch(Exception)
  {
     // return error with description about this step
  }
  try
  {       
      // Execute call to database with session and transaction object
      //
      // Actually in all function only this section of the code is different
      //
  }
  catch(Exception)
  {
      // Transaction object rollback
      // Return error with description for this step
  }
  finally
  {
      // Close session to database
  }
   return everything-is-ok  
}

所以 - 正如你所看到的,'prolog'(创建会话、事务、其他辅助函数)和'epilog'(关闭会话、回滚事务、清理模因等)对于所有函数都是相同的。

一些限制:

  • 我想将会话和事务对象的创建/销毁过程保留在功能中而不是在 ctor 中

  • 自定义代码(在中间运行的代码)必须包装在try/catch中,并针对不同情况返回不同的错误

  • 我愿意接受任何功能<>、操作<>首选任务<>功能建议

    设计模式或代码重构的任何想法?

带有序言和尾声的设计模式

这可以通过使用 IDisposable 对象来实现,例如:

using(var uow = new UnitOfWork() )
using(var t = new TransactionScope() )
{
   //query the database and throws exceptions
   // in case of errors
}

请不要,TransactionScope类是System.Transaction中的一个开箱即用的类,它(不仅)适用于数据库连接。在UnitOfWork中constructor做"序言"代码(即打开连接...),在Dispose做尾声部分。通过在出现错误时抛出异常,您可以确定无论如何都会调用尾声部分。

听起来您正在寻找模板方法模式。

模板方法模式将允许您通过仅提取方法的不同部分来减少类似方法中的重复代码量。

对于这个特定示例,您可以编写一个方法来执行所有繁琐的工作,然后调用回调来完成有趣的工作......

// THIS PART ONLY WRITTEN ONCE
public class Database
{
    // This is the template method - it only needs to be written once, so the prolog and epilog only exist in this method...
    public static IDatabaseError ExecuteQuery(Action<ISession> queryCallback)
    {
        try
        {
            //Initialize session to database
        }
        catch (Exception)
        {
            // return error with description for this step
        }
        try
        {
            // Try to create 'transaction' object
        }
        catch(Exception)
        {
            // return error with description about this step
        }
        try
        {       
            // Execute call to database with session and transaction object
            //
            // Actually in all function only this section of the code is different
            //
            var session = the session which was set up at the start of this method...
            queryCallback(session);
        }
        catch(Exception)
        {
            // Transaction object rollback
            // Return error with description for this step
        }
        finally
        {
            // Close session to database
        }
        return everything-is-ok
    }
}

这是用法:

// THIS PART WRITTEN MANY TIMES
IDatabaseError error = Database.ExecuteQuery(session =>
{
    // do your unique thing with the database here - no need to write the prolog / epilog...
    // you can use the session variable - it was set up by the template method...
    // you can throw an exception, it will be converted to IDatabaseError by the template method...
});
if (error != null)
    // something bad happened!

我希望这次我解释得更好:)