您无法在代码中同时获得简单的继承(签名和挂钩)和支持异步操作。
这两个目标是相互排斥的。
继承者必须了解直接(任务、异步)或间接(事件、回调函数、Auto(Manual)ResetEvents或其他同步结构)中的回调机制。其中一些是新的,一些是旧的。而且很难说哪一种更适合具体的使用情况。
好吧,看起来有一种简单的多线程代码方法,但是如果您DoRealJob
实际上会在另一个进程中运行或使用一些远程作业队列,那么真正的作业甚至会在您的应用程序之外执行呢?
所以:
- 如果你真的认为你的类将被用作一些异步工作者的基础,那么你应该相应地设计它。
- 如果不是 - 不要过度设计。你不能考虑任何可能的情况。只需足够好地记录您的课程,我怀疑有人会尝试
DoRealJob
异步实现,尤其是如果您将其命名为DoRealJobSynchronously
. 如果有人试图这样做,那么在这种情况下,你的良心就会非常干净。
编辑:
如果我同时提供 DoRealJob 的同步和异步版本以及标志 IsAsynchronous 以便我可以决定调用哪个版本,您认为这是否正确?
正如我已经说过的,我不知道您的实际使用场景。并且认为设计将能够有效地处理所有这些是不现实的。
还有两个非常重要的问题需要考虑,它们与您的整个Worker
班级及其DoJob
方法有关:
1)您必须确定该DoJob
方法是同步的还是异步的,还是要同时具有同步和异步版本?它与您的问题没有直接关系,但它仍然是非常重要的设计决策,因为它会对您的对象模型产生很大影响。这个问题可以改写为:
您是否希望该DoJob
方法在调用它之后阻止任何操作,直到它完成它的工作,或者您是否想将其作为某种StartJob
方法调用,这只会启动真正的处理,但它取决于其他机制在工作完成时通知您结束(或手动停止):
//----------------Sync worker--------------------------
SyncWorker syncWorker = CreateSyncStringWriter("The job is done");
Console.WriteLine("SyncWorker will be called now");
syncWorker.DoJob(); // "The job is done" is written here
Console.WriteLine("SyncWorker call ended");
//----------------Async worker--------------------------
Int32 delay = 1000;
AsyncWorker asyncWorker = CreateAsyncStringWriter("The job is done", delay);
Console.WriteLine("AsyncWorker will be called now");
asyncWorker.StartDoJob(); // "The job is done" won't probably be written here
Console.WriteLine("AsyncWorker call ended");
// "The job is done" could be written somewhere here.
2)如果您想DoJob
成为异步(或拥有异步版本),您应该考虑是否需要一些机制来通知 DoJob 何时完成处理 -异步编程模式,或者它何时或是否与您完全无关它结束了。
所以:
你有这两个问题的答案吗?
- 如果是 - 那很好。
- 如果不是 - 改进并考虑您的要求。
- 如果您仍然不确定 - 坚持使用简单的同步方法。
但是,如果您认为需要一些基于异步的基础架构,那么考虑到它是 C# 3.0,您应该使用异步编程模型。
为什么这是一个而不是基于事件的?因为 IAsyncResult 接口尽管笨重,但非常通用,可以很容易地用于基于任务的模型中,从而简化了未来向更高 .NET 版本的过渡。
它会是这样的:
/// <summary>
/// Interface for both the sync and async job.
/// </summary>
public interface IWorker
{
void DoJob();
IAsyncResult BeginDoJob(AsyncCallback callback);
public void EndDoJob(IAsyncResult asyncResult);
}
/// <summary>
/// Base class that provides DoBefore and DoAfter methods
/// </summary>
public abstract class Worker : IWorker
{
protected abstract void DoBefore();
protected abstract void DoAfter();
public IAsyncResult BeginDoJob(AsyncCallback callback)
{
return new Action(((IWorker)this).DoJob)
.BeginInvoke(callback, null);
}
//...
}
public abstract class SyncWorker : Worker
{
abstract protected void DoRealJobSync();
public void DoJob()
{
DoBefore();
DoRealJobSync();
DoAfter();
}
}
public abstract class AsyncWorker : Worker
{
abstract protected IAsyncResult BeginDoRealJob(AsyncCallback callback);
abstract protected void EndDoRealJob(IAsyncResult asyncResult);
public void DoJob()
{
DoBefore();
IAsyncResult asyncResult = this.BeginDoRealJob(null);
this.EndDoRealJob(asyncResult);
DoAfter();
}
}
PS:此示例不完整,未经测试。
PPS:您也可以考虑使用委托代替抽象(虚拟)方法来表达您的工作:
public class ActionWorker : Worker
{
private Action doRealJob;
//...
public ActionWorker(Action doRealJob)
{
if (doRealJob == null)
throw new ArgumentNullException();
this.doRealJob = doRealJob;
}
public void DoJob()
{
this.DoBefore();
this.doRealJob();
this.DoAfter();
}
}
DoBefore
并且DoAfter
可以用类似的方式表达。
PPPS: Action
delegate 是 3.5 的构造,因此您可能必须定义自己的接受零参数并返回 void 的委托。
public delegate void MyAction()