Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Logische Operatoren als Aufzählungstyp (https://www.delphipraxis.net/183185-logische-operatoren-als-aufzaehlungstyp.html)

bernau 18. Dez 2014 15:09

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von Mavarik (Beitrag 1283960)
Zitat:

Zitat von bernau (Beitrag 1283948)
Zitat:

Zitat von Dejan Vu (Beitrag 1283945)
Klar, aber er hat vielleicht ein ganzes Array und möchte das dynamisch machen...

Richtig.

???

Delphi-Quellcode:
result2 := meineFunktion(loAnd,[Value1,Value2,Value3]);
Sieht mir nicht Dynamisch aus, sondern wie variable Parameter Anzahl...

Aber egal DU must ja wissen was Du brauchst...

Das hier war jetzt ein Beispiel. Könnte aber auch folgendes machen

Delphi-Quellcode:
result2 := meineFunktion(loAnd,EinDynArrayWelches200WerteHabenKann);

bernau 18. Dez 2014 15:28

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von Stevie (Beitrag 1283953)
Zitat:

Zitat von Dejan Vu (Beitrag 1283919)
Wieso führst Du überhaupt einen Enum ein? Schreib doch einfach die paar Methoden separat? Oder mach es mit einzelnen Klassen. Dann verzichtest Du auf dein 'case'-Statement, was in einer sauberen Methode ohnehin nichts zu suchen hat (sagen die Puristen).

Hättest du das nicht geschrieben, hätte ich es jetzt getan :thumb:
Guckstu das

Den Enum wollte ich einführen, da ich die Logische Operation Dynamisch ermitteln wollte.

Delphi-Quellcode:
Procedure Irgendetwas;
var
  lOperator:TLogicalOperator;
  lMeinArray:TDoubleDynArray;
begin
  lOperator:=GibMirDenOperator;
  FuelleMeinArray(lMeinArray);
  MeineFunktion(lOperator,lMeinArray);
 
  lOperator:=GibMirEinenAnderenOperator;
  FuelleMeinArrayMitAnderenWerten(lMeinArray);
  MeineFunktion(lOperator,lMeinArray);
end;
Würde ich den Operator nicht in "MeineFunktion" verwenden, würde es ja so aussehen:


Delphi-Quellcode:
Procedure Irgendetwas;
var
  lOperator:TLogicalOperator;
  lMeinArray:TDoubleDynArray;
begin
  lOperator:=GibMirDenOperator;
  FuelleMeinArray(lMeinArray);
  case loperator of
    loAnd:MeineFunktionAnd(lMeinArray);
    loOr:MeineFunktionOr(lMeinArray);
  end;
 
  lOperator:=GibMirEinenAnderenOperator;
  FuelleMeinArrayMitAnderenWerten(lMeinArray);
  case loperator of
    loAnd:MeineFunktionAnd(lMeinArray);
    loOr:MeineFunktionOr(lMeinArray);
  end;
end;

bernau 18. Dez 2014 15:30

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von Dejan Vu (Beitrag 1283919)
Dann verzichtest Du auf dein 'case'-Statement, was in einer sauberen Methode ohnehin nichts zu suchen hat (sagen die Puristen).

Das hatte ich ganz übersehen. Kannst du mir das mal genauer erklären, weshalb man ein Case nicht benutzen sollte.

Stevie 18. Dez 2014 15:56

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von bernau (Beitrag 1283977)
Zitat:

Zitat von Dejan Vu (Beitrag 1283919)
Dann verzichtest Du auf dein 'case'-Statement, was in einer sauberen Methode ohnehin nichts zu suchen hat (sagen die Puristen).

Das hatte ich ganz übersehen. Kannst du mir das mal genauer erklären, weshalb man ein Case nicht benutzen sollte.

Schau dir das Video an, was ich verlinkt habe, viel besser kann man das nicht erklären.

bernau 18. Dez 2014 16:02

AW: Logische Operatoren als Aufzählungstyp
 
Ja. Kurz. 40Min. Andere Sprache (C++).....

Wenn man so etwas in 3-4 Sätzen zusammenfassen könnte, ist das bestimmt um den Überblick zu erhalten besser.

Die Details kann man dann ja im Video anschauen.

Stevie 18. Dez 2014 16:41

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von bernau (Beitrag 1283987)
Ja. Kurz. 40Min. Andere Sprache (C++).....

Wenn man so etwas in 3-4 Sätzen zusammenfassen könnte, ist das bestimmt um den Überblick zu erhalten besser.

Die Details kann man dann ja im Video anschauen.

Java, nich C++ 8-)

Du hast zwar den case in dem aufrufenden Code vermieden, aber nun wird deine Routine, der du die Operation übergibst zu ner Monsterfunktion, die mehrere Operationen kann. Warum nicht 2 verschiedene Funktionen?

Nun mag nicht übermorgen jemand mit ner neuen Logischen Operation, die er entdeckt hat, um die Ecke kommen, aber kennt bestimmt jeder case of und 1, 2, 3 sind behandelt und huch, da hat man ja noch Fall 4 vergessen, wird hinzugefügt und muss nun überall wo man mal nen case auf diesen enum oder was gemacht hat, nachgepflegt werden. Und eh man sich versieht, hat man ne zighundert Zeilen Methode, die opBrötchenbacken, opKaffeekochen und opStaubsaugen kann. Also 3 verschiedene Methoden.

Und da kommt das Zauberwort Polymorphie ins Spiel, da kann ich mir eine Basisklasse (oder auch ein Interface) bauen, was mir meine Operation (oder auch Strategie) abbildet.

Wie man da hin kommt, kann unterschiedlich sein. Ich persönlich find die Kombination von arrays und enums herrlich, da knallts nämlich direkt beim Kompilieren, wenn jemand mal einen neuen Wert hinzugefügt hat und nicht alle cases gefunden und angepasst hat (kennt man ja, case of ... else raise exception.Create('unbehandelter Fall!') end :wall:).


Ich blas das Beispiel aber nun auch gar nicht unnötigerweise mit OOP auf sondern bleib mal bei der prozeduralen Programmierung,
da lässt sich das Prinzip nämlich auch anwenden:

Delphi-Quellcode:
type
  TArrayOperation = procedure(const values: TDoubleDynArray);
  TLogicalOperator = (loAnd, loOr);

procedure AndDings(const values: TDoubleDynArray);
begin
  // ...
end;

procedure OrDings(const values: TDoubleDynArray);
begin
  // ...
end;

const
  ArrayOperations: array[TLogicalOperator] of TArrayOperation = (
    AndDings,
    OrDings
  );

Procedure Irgendetwas;
var
  MeineFunktion: TArrayOperation;
  lMeinArray: TDoubleDynArray;
begin
  MeineFunktion := GibMirDieOperation;
  FuelleMeinArray(lMeinArray);
  MeineFunktion(lMeinArray);

  MeineFunktion := GibMirEineAndereOperation;
  FuelleMeinArrayMitAnderenWerten(lMeinArray);
  MeineFunktion(lMeinArray);
end;
In der Irgendetwas Prozedur hast du nun überhaupt nix mehr mit dem enum am Hut und sagst einfach nur, ich brauche eine Operation, gib die mir, damit ich sie aufrufen kann. Und das komplette Mapping ist in diesem Fall hardcoded und kann vom Compiler geprüft werden (in Fällen wo das dynamisch ist, würde sich ein Dictionary anbieten, wo man seine strategien registriert).

Das Beispiel mit der Polymorphie und wie man dadurch auf cases in Klassen verzichten kann, kannst du dir ja dann in Ruhe anschauen (auch wenns Java is :twisted:).

Dejan Vu 18. Dez 2014 17:59

AW: Logische Operatoren als Aufzählungstyp
 
Ich wollte mit Klassenfabriken kommen, aber so ist das schön leichtgewichtig.

Eine Class Factory wäre vielleicht ein wenig oversized für die kleine Geschichte, aber als Übung vielleicht nett
(Kann kein Delphi mehr, daher bitte kleine Fehler entschuldigen).
Delphi-Quellcode:
Type
  ILogicalArrayCompressor = interface
    function Execute (array : TSomeArray);
  end;

  TAndArrayCompressor = class (ILogicalArrayCompressor)
  public function Execute (array : TSomeArray);
  end;
   
  TOrArrayCompressor = class (ILogicalArrayCompressor)
  public function Execute (array : TSomeArray);
  end;

  TArrayCompressorFactory = class
    class function Create (logicalOperator : TLogicalOperator) : ILogicalArrayCompressor;
  end;

class function TArrayCompressorFactory.Create (logicalOperator : TLogicalOperator) : ILogicalArrayCompressor;
begin
  case logicalOperator of
   laOr : result := TOrArrayCompressor.Create();
   laAnd : result := TAndArrayCompressor.Create();
// Add new operators here
   else raise ArgumentException.Create('Unknown logical Operator');
 end;
End;
---
Function TUserClass.Calculate (logicalOperator : TLogicalOperator; SomeArray : TSomeArray) : Integer;
Begin
  result := TArrayCompressorFactory.Create(logicalOperator).Execute(SomeArray);
End;
Hä? Eben meint der Typ doch, 'case' ist Müll, und dann klatscht er das doch rein? Ja. 'Case' ist sollte vermieden werden, außer in Klassenfabriken (da ist das legitim). Sagen andere Puristen. Wie schön, wenn sich Softwaretechniker so einig sind :lol:

Das Schöne an so einer Methode (oder der von Stevie) ist doch die: Der Anwender hat ein Array und eine Operation (egal welche) und will, das die Arrayelemente entsprechend verknüpft/verdichtet werden. Welche Operationen es gibt, ist im wurscht.

Wenn Du das so umsetzt, kannst Du die Anwenderklasse zu machen, d.h. Du musst sie nicht mehr anfassen, bloß weil eine neue logische Operation hinzugekommen ist. Das bedeutet aber auch, das Du keinen Bockmist mit der Klasse (aus Versehen!) machen kannst (weil Du sie noch nicht einmal neu kompilierst). Sie läuft, ist getestet und der Quellcode ist im Tresor. Du erweiterst trotzdem die Mächtigkeit der Klasse.

Natürlich musst Du den Code anfassen, wenn ein logischer Operator dazukommt. Aber die Änderungen sind viel simpler und bergen vor allen Dingen nicht die Gefahr, Code in der Nähe aus Versehen zu zerballern oder kaputt zu optimieren (ein beliebtes Hobby).

Also ich find das praktisch.

DeddyH 18. Dez 2014 18:20

AW: Logische Operatoren als Aufzählungstyp
 
Wenn sich die Klassen/Interfaces in der Factory registrieren, kann diese das schön in z.B. einem Dictionary ablegen. Damit entfällt dann auch die Case-Abfrage, es wird einfach im Dictionary nach dem passenden Interface/der Klasse gesucht und bei Fund die entsprechende Instanz zurückgegeben. Dafür müsste es im Forum auch Beispiele geben, ich bin nur gerade zu faul zum Suchen.

bernau 18. Dez 2014 18:26

AW: Logische Operatoren als Aufzählungstyp
 
@Stevie: Das sieht erst mal sehr interessant aus. Leuchtet mir ein, daß man bei einer Erweiterung des Aufzählungstyp der Compiler eine Fehlermeldung gibt und man nichts vergessen kann. Muss ich mal probieren.

Allerdings kann ich mir vorstellen, daß das Debuggen nicht so schön ist. Bei "GibMirDieOperation" bekomme ich normalerweise den Aufzählungstyp zurück und der wird mir im Debugger angezeigt. Bei der deiner Funktion bekomme ich ja nicht den Namen der Procedure angezeigt sondern den Pointer. Denke ich.

@Dejan Vu: Ist wirklich etwas oversized und auch in deinem Fall weis ich nicht, ob es wirklich angenehm zu debuggen ist. Und mit interfaces stehe ich sowiso auf dem Kriegsfuß. Aber egal. Ich schaue es mir mal an.

Danke

Stevie 18. Dez 2014 19:25

AW: Logische Operatoren als Aufzählungstyp
 
Zitat:

Zitat von Dejan Vu (Beitrag 1284012)
Hä? Eben meint der Typ doch, 'case' ist Müll, und dann klatscht er das doch rein? Ja. 'Case' ist sollte vermieden werden, außer in Klassenfabriken (da ist das legitim). Sagen andere Puristen. Wie schön, wenn sich Softwaretechniker so einig sind :lol:

Pff, wer braucht schon case... haste ja den gleichen Müll dann, dass du erst zur Laufzeit irgendwo merkst dass dort nen Operator nicht behandelt wird. :)

Delphi-Quellcode:
  TBaseArrayCompressor = class(TInterfacedObject, ILogicalArrayCompressor)
  public
    procedure Execute(arr: TSomeArray); virtual; abstract;
  end;

  TBaseArrayCompressorClass = class of TBaseArrayCompressor;

  TAndArrayCompressor = class(TBaseArrayCompressor)
  public
    procedure Execute(arr: TSomeArray); override;
  end;

  TOrArrayCompressor = class(TBaseArrayCompressor)
  public
    procedure Execute(arr: TSomeArray); override;
  end;

  TArrayCompressorFactory = class
    class function Create(logicalOperator : TLogicalOperator) : ILogicalArrayCompressor;
  end;

class function TArrayCompressorFactory.Create (logicalOperator : TLogicalOperator) : ILogicalArrayCompressor;
const
  CompressorClasses: array[TLogicalOperator] of TBaseArrayCompressorClass = (
    TOrArrayCompressor, TAndArrayCompressor);
begin
  Result := CompressorClasses[logicalOperator].Create;
end;
Dasselbe würde auch mit einer class procedure funktionieren, sofern die array compressor Klassen stateless sind. Unnötig, die dann zu instanzieren.

Zitat:

Zitat von bernau (Beitrag 1284017)
@Stevie: Das sieht erst mal sehr interessant aus. Leuchtet mir ein, daß man bei einer Erweiterung des Aufzählungstyp der Compiler eine Fehlermeldung gibt und man nichts vergessen kann. Muss ich mal probieren.

Allerdings kann ich mir vorstellen, daß das Debuggen nicht so schön ist. Bei "GibMirDieOperation" bekomme ich normalerweise den Aufzählungstyp zurück und der wird mir im Debugger angezeigt. Bei der deiner Funktion bekomme ich ja nicht den Namen der Procedure angezeigt sondern den Pointer. Denke ich.

Debugger sind schlaue Kerlchen, der löst das richtig auf (ist ja nicht nur Pointer sondern nen Prozedurzeiger) und zeigt dir dann in den lokalen Variablen:
Delphi-Quellcode:
MeineFunktion MyUnit.AndDings
.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:41 Uhr.
Seite 3 von 3     123   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz