2

我正在寻找可以实现一些序言代码然后是结语代码的设计模式。让我解释:

我有一个功能(很多)几乎做同样的事情:

这是 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 中,并针对不同的情况返回不同的错误

  • 我愿意接受任何 Func<>、Action<> 更可取的 Task<> 功能建议

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

4

2 回答 2

3

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

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

请注意,TransactionScope类是 System.Transaction 中的一个开箱即用的类,它(不仅)适用于数据库连接。在 UnitOfWorkconstructor中执行“Prologue”代码(即打开连接...),在Dispose结尾部分执行。通过在发生错误时抛出异常,您可以确定结尾部分无论如何都会被调用。

于 2012-06-13T08:57:01.303 回答
2

听起来您正在寻找Template Method Pattern

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

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

// 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!

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

于 2012-06-13T09:29:05.130 回答