Tim Barclay
Tim Barclay

Reputation: 855

Design pattern for surrounding code in start, complete and fail methods

Suppose I have various arbitrary sections of code to run, but before each section, I have to run a Start() method and then after each section I need to run a Complete() method. However, if an exception is thrown in the code section, I want to run a Fail(string message) method instead of Complete(). Is there a design pattern that elegantly encapsulates this to make it neat and easily repeatable?

For example, let's say I have a type called Thing that contains a Start() method that adds a row to a logging db table to reflect that a task is in progress, a Complete() method that changes that row to reflect that the task finished and a Fail(string message) method that changes the row to reflect that the task failed. These are just examples though, they could be doing any set-up and tidy up type tasks.

The naive implementation might be simply to call those methods manually:

public void DoStuff()
{
    var thing = new Thing();
    thing.Start();
    try
    {
        DoImportantStuff();
        thing.Complete();
    }
    catch (Exception e)
    {
        thing.Fail(e.Message);
    }
}

But if I'm going to have to repeat this in a lot of different places, it ends up creating quite a lot of duplication and it might be easy to forget to call Complete or mess this up in some subtle way.

In C#, there's the using pattern, which provides a good way of encapsulating most of this. For example, if my Thing type looked like this:

public class Thing : IDisposable
{
    public Thing(){
        Start();
    }

    private void Start() { /* start */ }
    private void Complete() { /* complete */ }

    public void Dispose()
    {
        Complete();
    }
}

My DoStuff() method could now be simplified to this:

public void DoStuff()
{
    using(new Thing())
    {
        DoImportantStuff();
    }
}

Which is much nicer. But it doesn't allow me to call Fail instead of Complete if an exception is thrown because (I think!) the Dispose method is essentially called in a Finally block.

I have thought of having a try/catch inside the using block and then setting a thing.HasFailed flag inside the catch block and then using that in the Dispose method to decide whether to Complete or Fail. But that seems a bit fiddly and I'd like the consumer of Thing to have to do as little as possible to make it work correctly.

So is there a design pattern that encapsulates what I want to do and avoids the need to manually write a try\catch each time?

Upvotes: 3

Views: 204

Answers (3)

Thomas
Thomas

Reputation: 644

The pattern is called "template method". You can find your implementation under the title "aspect oriented programming". (https://msdn.microsoft.com/en-us/library/aa288717(v=vs.71).aspx)

Upvotes: 1

sameerkn
sameerkn

Reputation: 2259

Using 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();

Upvotes: 0

Ofir Winegarten
Ofir Winegarten

Reputation: 9365

You could have a Thing like this:

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);
      }

  }
}

And Use it like this:

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

Upvotes: 5

Related Questions