开始,完整和失败方法中周围代码的设计模式

时间:2017-01-25 11:19:27

标签: c# design-patterns

假设我有各种各样的代码段要运行,但在每个部分之前,我必须运行Start()方法,然后在每个部分之后我需要运行Complete()方法。但是,如果代码部分中抛出异常,我想运行Fail(string message)方法而不是Complete()。是否有优雅的设计模式,使其整洁,易于重复?

例如,假设我有一个名为Thing的类型,它包含一个Start()方法,该方法向记录数据库表添加一行以反映任务正在进行中,{{1}更改该行以反映任务完成的方法以及更改行以反映任务失败的Complete()方法。这些只是一些例子,他们可以做任何设置和整理类型的任务。

天真的实现可能只是手动调用这些方法:

Fail(string message)

但如果我要在很多不同的地方重复这个问题,最终会造成很多重复,很容易忘记调用public void DoStuff() { var thing = new Thing(); thing.Start(); try { DoImportantStuff(); thing.Complete(); } catch (Exception e) { thing.Fail(e.Message); } } 或者把它搞砸了微妙的方式。

在C#中,有Complete模式,它提供了封装大部分内容的好方法。例如,如果我的using类型如下所示:

Thing

我的public class Thing : IDisposable { public Thing(){ Start(); } private void Start() { /* start */ } private void Complete() { /* complete */ } public void Dispose() { Complete(); } } 方法现在可以简化为:

DoStuff()

哪个更好。但是如果抛出异常,它不允许我调用public void DoStuff() { using(new Thing()) { DoImportantStuff(); } } 而不是Fail,因为(我认为!)Complete方法基本上是在Dispose块中调用的

我想过在Finally块中有一个try/catch,然后在using块内设置一个thing.HasFailed标志,然后在catch中使用它}方法来决定是Dispose还是Complete。但这似乎有点繁琐,我希望Fail的消费者尽可能少地做,以使其正常工作。

那么是否有一个设计模式封装了我想要做的事情,并且每次都不需要手动编写Thing

3 个答案:

答案 0 :(得分:5)

你可以这样Thing

public class Thing 
{
  private void Start() { /* start */ }
  private void Complete() { /* complete */ }
  private void Fail(string message) {}

  public void DoAction(Action action)
  {
      this.Start();
      try 
      {
        action();
        this.Complete();
      }
      catch (Exception e)
      {
        this.Fail(e.Message);
      }

  }
}

并像这样使用它:

Thing thing = new Thing();
thing.DoAction(this.DoStuff);

答案 1 :(得分:1)

该模式称为“模板方法”。您可以在“面向方面编程”标题下找到您的实现。 (https://msdn.microsoft.com/en-us/library/aa288717(v=vs.71).aspx

答案 2 :(得分:0)

使用Delegates

public class Thing : IDisposable
{
    private void Start() { /* start */ }
    private void Complete() { /* complete */ }
    private void Fail(string _szMessage) {/* fail */}

    public delegate void ProcessClientStuff();

    private ProcessClientStuff m_delegateClientStuff;

    public Thing(ProcessClientStuff _delegateClientStuff) {m_delegateClientStuff = _delegateClientStuff}

    public void Dostuff()
    {
        Start();

        try
        {
            m_delegateClientStuff();
            Complete();
        }
        catch(Exception e)
        {
            Fail(e.Message);
        }
    }    
}


void ClientStuff()
{
    Console.WriteLine("Hello");
}

Thing oClientStuffProcessor = new Thing(ClientStuff);
oClientStuffProcessor.Dostuff();