Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#10

Re: Sinnvoller Einsatz von goto

  Alt 20. Mär 2010, 06:39
Da die Funktion zwei Aufgaben erfüllt (sende Nachrichten und räume auf), teilen wir sie. Da ein Goto zu 99.9% der Fälle eine Aufgabe beendet, fällt das Goto nun automatisch weg. Das ist kein Trick, sondern sowieso Pflicht, um das SRP (Single Responsibility Princip) auf funktionaler Ebene einzuhalten.
Delphi-Quellcode:
procedure TryHardToSendMessages (aParentHandle : THandle);
var
  i: Integer;

begin
  for i := 0 to 9 do begin
    if Abort then begin
      SendMessage(ParentHandle, CM_ABORT, 0 , 0);
      exit;
    end;
    SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
    Sleep(500);
  end;
  SendMessage(ParentHandle, CM_FINISHED, 0, 0);
End;

function DemoThread(p: Pointer): Integer;
begin
  Try
    TryHardToSendMessages (PThreadParams(p)^.ParentHandle);
  Finally
    Dispose(p);
  End;
  Result := 0;
end;
Hmm. Das mit der Schleife und dem Abort-Flag geht ja nun mal gar nicht (Abort ist ein reserviertes Schlüsselwort):
Außerdem und überhaupt ist nicht so richtig klar, wie die Nachrichten verwendet werden sollen. Mal sehen:

Wir senden 10x eine Nachricht 'CM_STATUS'. Nach jeder Nachricht warten wir 500ms.
Wenn alle 10 Nachrichten verschickt haben, senden wir ein 'CM_FINISHED'.
Wurden wir ausnahmsweise (<-Zaunpfahl) unterbrochen, senden wir ein CM_ABORT.
Delphi-Quellcode:
Procedure TryHardToSendMessages (aParentHandle : THandle);
var
  i: Integer;

begin
  Try
    for i := 0 to 9 do
      if ExternalAbort then
        abort
      else begin
        SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
        Sleep(500);
      end
  
    SendMessage(ParentHandle, CM_FINISHED, 0, 0);
  Except
// TODO: Vollständige Exceptionbehandlung
    SendMessage(ParentHandle, CM_ABORT, 0 , 0);
   end;
end;
Hier eine Alternative ohne Exceptions, sondern mit einer Funktion, die den Erfolg als Rückgabewert liefert.
Delphi-Quellcode:
Function Sending10MessagesWasNotAborted(aParentHandle) : Boolean;
Var
  i : Integer;

Begin
  for i := 0 to 9 do
    if ExternalAbort then
      break
    else begin
      SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
      Sleep(500);
    end;
  Result := ExternalAbort;
End;
  
Procedure TryHardToSendMessages (aParentHandle : THandle);
begin
  If Sending10MessagesWasNotAborted(aParentHandle) Then
    SendMessage(ParentHandle, CM_FINISHED, 0, 0)
  else
    SendMessage(ParentHandle, CM_ABORT, 0 , 0);
end;
Das ist -finde ich- noch lesbarer.
Nachteil der 2.Variante bzw. des dort verwendeten Verfahrens: Wenn dieses Paradigma durchgezogen wird, entstehen schnell verschachtelte und unleserliche If-Then-Abläufe, z.B.:
Delphi-Quellcode:
..
  If Action1IsSuccessfull then
    If Action2IsSuccessfull then
      If Action3IsSuccessfull then
        DoSomething
      else
        HandleException
    else
      HandleException
  else
    HandleException
..
Dann lieber so (Try-Except-Paradigma)
Delphi-Quellcode:
...
Try
  Action1;
  Action2;
  Action3;
Except
  HandleException;
End;
Paradigmen sollten zwar stringent durchgezogen werden, aber wozu sind solche Regeln da, wenn nicht zum brechen?
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat