Reputation: 855
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
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
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
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