Asynchrone Kommunikation mit dem Async-Pattern (Refactored)
Geschrieben von Thomas Christian in Architektur, Pattern, TippsNach dem ich meinen vorherigen Artikel zum Thema “Asynchrone Kommunikation mit dem Async-Pattern” vorgestellt hatte, hat Ralf Westphal auf seinem Blog “One Man Think Tank Gedanken” das Vorgehen zur Implementierung einer asynchronen Kommunikation mit Hilfe von Event-Based-Components vorgestellt, welches eine sehr gute Alternative zum Async-Pattern ist. Seinen Eintrag nehme ich zum Anlass, um meine Beispiel-Implementierung des Async-Pattern zu refaktorisieren, um eine bessere Trennung der Verantwortlichkeiten und somit eine bessere Lesbarkeit zu erreichen.
In das Form wird die Abhängigkeit “CalcProxy” injected.
static void Main()
{
CalcProxy calcProxy = new CalcProxy(new Calculator());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(calcProxy));
}
Im Gegensatz zur vorherigen Version wird in der Form nun nicht mehr der Calculator direkt erzeugt und verwendet, sondern auf den injekteten CalcProxy zugegriffen.
public partial class Form1 : Form {
private readonly ICalcProxy m_calcProxy;
public Form1(ICalcProxy calcProxy) {
InitializeComponent();
m_calcProxy = calcProxy;
m_calcProxy.CalcCompleted += CalculatorCalcCompleted;
}
private void Run_Click(object sender, EventArgs e) {
int number;
if (Int32.TryParse(txbEingabe.Text, out number)) {
m_calcProxy.CalcAsync(number, number);
}
}
void CalculatorCalcCompleted(object sender, CalcEventArgs eventArgs) {
lblCounter.Text = eventArgs.UserState.ToString();
}
}
Der CalcProxy wiederum bekommt die Abhängigkeit zum Calculator injected und stellt für die Calculator.Calc-Methode sowohl eine synchrone als auch eine asynchrone Methode zur Verfügung.
public class CalcProxy : ICalcProxy {
private readonly ICalculator m_calculator;
public event CalcCompletedEventHandler CalcCompleted;
private AsyncOperation m_asyncOperation;
private bool m_isRunning;
public CalcProxy(ICalculator calculator) {
m_calculator = calculator;
}
public int Calc(int number) {
return m_calculator.Calc(number);
}
public void CalcAsync(int number, object userState) {
lock (this) {
if (m_isRunning) {
throw new InvalidOperationException("Diese Operation wird bereits ausgeführt");
}
m_isRunning = true;
m_asyncOperation = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(ExecuteCalc, number);
}
}
private void ExecuteCalc(object state) {
var result = Calc((int)state);
m_asyncOperation.PostOperationCompleted(CalcCompletedSuccessful, result);
}
private void CalcCompletedSuccessful(object result) {
if (CalcCompleted != null) {
CalcCompleted(this, new CalcEventArgs(null, false, (int)result, result));
}
}
}
Nun enthält der Calculator nur noch die Methode die für den Calculator notwendig ist, nämlich die Calc-Methode.
public class Calculator : ICalculator {
public int Calc(int number) {
Thread.Sleep(10000);
return number * number;
}
}

Einträge (RSS)