[英]Design pattern: child class calling base class
我有“處理程序”能夠觸發“經紀人”(一個做某事的對象 - 這里不重要)。
處理程序正在偵聽不同類型的事件:
每個處理程序必須:
每個處理程序應該
我想從基本的Handler類中觸發代理,因此我集中了我的邏輯(觸發事件,捕獲異常,管理線程等)。 但是,基本處理程序不知道如何調用代理(何時調用此函數,要將哪些參數發送到Process方法)>>只有專門的子處理程序才知道如何執行此操作。
我找到的唯一方法是在基本處理程序中實現一個接受Action參數的Execute方法......我不喜歡這種方法,因為它不是真正的直接(孩子需要調用基類,否則沒有任何反應)。 我希望找到一個更好的設計來處理這個問題。 另外我可以告訴你我的開發人員會告訴我他們不懂如何使用系統。
abstract class Handler : IHandler
{
public IBroker Broker { get; protected set; }
public event ProcessedEventHandler Processed;
protected void OnProcessed(ProcessExecutionResult result) => Processed?.Invoke(this, result);
public static IHandler Create(IBroker broker)
{
if (broker is ITimerTriggeredBroker)
return new TimeHandler((ITimerTriggeredBroker)broker);
return null;
}
protected Handler(IBroker broker)
{
if (broker == null) throw new ArgumentNullException(nameof(broker));
Broker = broker;
}
public abstract void Start();
public abstract void Stop();
protected void Execute(Action action)
{
var res = new ProcessExecutionResult();
try
{
action?.Invoke();
res.IsSuccess = true;
}
catch (Exception ex)
{
res.Exception = ex;
res.IsSuccess = false;
}
finally
{
OnProcessed(res);
}
}
}
TimeHandler(處理與時間相關的事件)
class TimeHandler : Handler
{
private readonly Timer _timer;
private readonly DateTime _start;
private readonly TimeSpan _frequency;
public TimeHandler(ITimerTriggeredBroker broker)
: base(broker)
{
_start = broker.Trigger.StartTime;
_frequency = broker.Trigger.Frequency;
_timer = new Timer(_ => Execute(broker.Process));
}
(...)
}
FileHandler(處理FileSystem相關事件)
class FileHandler : Handler
{
private readonly FileSystemWatcher _watcher = new FileSystemWatcher();
public FileHandler(IFileTriggeredBroker broker)
: base(broker)
{
if (!Directory.Exists(broker.Trigger.DirectoryPath))
throw new DirectoryNotFoundException("Unable to locate the supplied directory");
_watcher.Filter = broker.Trigger.Filter;
_watcher.Path = broker.Trigger.DirectoryPath;
_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName |
NotifyFilters.FileName;
_watcher.Created += (s, a) =>
{
if (IsCopied(a.FullPath)) Execute(() => broker.Process(a.FullPath));
};
}
您要實現的目標有幾個方面:
架構應易於理解,並由程序員遵循。 它應該在他們編程時指導他們並保護他們不犯錯誤。
它應該是健壯的。 例如,您應該保證處理在監視文件夾中創建的每個文件。
在我的回答中,我將忽略健壯性方面。 請認真看待這個。 FileSystemWatcher無法保證提供所有創建的文件。 此外,建議您在單獨的線程中分離FileSystemWatcher事件的處理,或者為此使用.NET任務。
此外,我認為您應該考慮使用隊列,如Microsoft MQ,Azure Queue,RabbitMQ。 您可以直接執行此操作或使用MassTransit等系統。
下面我提出一個架構,它將使您的程序員更容易構建。
將應用程序划分到文件夾或不同的程序集中,以便在框架和特定處理程序/代理之間進行明確分離。
對於每種類型的處理,我們創建一個特定的消息類,讓處理程序和代理實現一個特定於消息類型的通用接口。
我們將使用C#高級類型系統來確保它很難出錯,並且編譯器將幫助程序員使用正確的東西。 為此,我們使用基於消息類型類的通用接口和類。
在這里,我們將設置一個管理器,它將使用各自的消息注冊所有處理程序和代理。 這是一個獨立的例子,我建議你使用一個依賴注入系統,例如AutoFac來進一步優化它。
static void Main(string[] args)
{
var manager = new Manager();
manager.Register<FileHandlerMessage>(new FileHandler(), new FileBroker());
manager.Register<TimeHandlerMessage>(new TimeHandler(), new TimeBroker());
manager.Start();
Console.ReadLine();
manager.Stop();
}
Manager類的作用是組織正確使用處理程序和代理。
class Manager
{
private List<IGenericHandler> handlers = new List<IGenericHandler>();
public void Register<M>(IHandler<M> handler, IBroker<M> broker) where M : Message
{
handlers.Add(handler);
}
public void Start()
{
foreach ( var handler in handlers )
{
handler.Start();
}
}
public void Stop()
{
foreach (var handler in handlers)
{
handler.Stop();
}
}
}
對於每種類型的代理,我們將定義一個特定的消息類,派生自一個公共基類:
abstract class Message
{
}
class FileHandlerMessage : Message
{
public string FileName { get; set; }
}
interface IGenericHandler
{
void Start();
void Stop();
}
interface IHandler<M> : IGenericHandler where M : Message
{
void SetBroker(IBroker<M> broker);
}
class FileHandler : IHandler<FileHandlerMessage>
{
private IBroker<FileHandlerMessage> broker;
public FileHandler()
{
}
public void SetBroker(IBroker<FileHandlerMessage> fileBroker)
{
this.broker = fileBroker;
}
public void Start()
{
// do something
var message = new FileHandlerMessage();
broker.Process(message);
}
public void Stop()
{
// do something
}
}
class TimeHandler : IHandler<TimeHandlerMessage>
{
private IBroker<TimeHandlerMessage> broker;
public void SetBroker(IBroker<TimeHandlerMessage> broker)
{
this.broker = broker;
}
public void Start()
{
// do something
var message = new TimeHandlerMessage();
broker.Process(message);
}
public void Stop()
{
// do something
throw new NotImplementedException();
}
}
class FileBroker : IBroker<FileHandlerMessage>
{
public void Process(FileHandlerMessage message)
{
throw new NotImplementedException();
}
}
class TimeBroker : IBroker<TimeHandlerMessage>
{
public void Process(TimeHandlerMessage message)
{
throw new NotImplementedException();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.