在启动、完成和失败方法中围绕代码的设计模式



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

例如,假设我有一个名为Thing的类型,它包含一个Start()方法,该方法将一行添加到日志数据库表中以反映任务正在进行中,一个Complete()方法,它将更改该行以反映任务已完成,一个Fail(string message)方法,它更改该行来反映任务失败。不过,这些只是示例,它们可以执行任何设置和整理类型的任务。

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

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

但是,如果我不得不在很多不同的地方重复这一点,它最终会产生大量的重复,可能很容易忘记调用Complete,或者以某种微妙的方式将其搞砸。

在C#中,有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块中调用的。

我已经考虑过在using块内具有try/catch,然后在catch块内设置thing.HasFailed标志,然后将其用于Dispose方法来决定是Complete还是Fail。但这似乎有点麻烦,我希望Thing的消费者必须尽可能少地做才能使其正常工作。

那么,是否有一种设计模式可以封装我想要做的事情,并避免每次手动编写trycatch

您可以拥有这样的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);

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

使用委托。

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

最新更新