AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Globale Variablen/Abhängigkeiten = Böse... Und nu?
Thema durchsuchen
Ansicht
Themen-Optionen

Globale Variablen/Abhängigkeiten = Böse... Und nu?

Ein Thema von Dejan Vu · begonnen am 19. Mai 2014 · letzter Beitrag vom 13. Jun 2014
Antwort Antwort
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.645 Beiträge
 
#1

AW: Globale Variablen = Böse... Und nu?

  Alt 19. Mai 2014, 08:58
Ja, das ist wirklich so gewollt.
Du willst das aber - aus guten Gründen - nicht immer alles von Hand zusammenstöpseln.

Ein guter IoC-Container nimmt Dir diese Arbeit ab und löst die Abhängigkeiten selber auf und instanziert Dir diese Klassen mit den Monster-Konstruktoren von alleine.

Du kannst natürlich auch dort, wo es Sinn macht, Argumente zusammenfassen.
z.B. der UIWrapper und den Report (Ein- / Ausgabe für den User) und den CurrentUser, die Connection und das technische Logging (Context).

Die Datenbankverbindung / Transactionhandling und das Logging würde man im übrigen vermutlich eher über Aspekte als über DI lösen, aber prinzipiell passt das sonst so.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Globale Variablen = Böse... Und nu?

  Alt 19. Mai 2014, 09:16
Kann es sein, dass der Titel falsch ist?

Bis jetzt geht es um globale Abhängigkeiten und nicht um globale Variablen wie der Titel vermuten lässt.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#3

AW: Globale Variablen = Böse... Und nu?

  Alt 19. Mai 2014, 09:23
Albern ist das richtige Wort.
Einerseits ja, andererseits nein. Das Dilemma der globalen Abhängigkeiten ist nicht von der Hand zu weisen. Und wenn man den Weg gehen will, seine Anwendungen auch übermorgen noch modern zu halten, führt leider kein Weg daran vorbei.

Ein guter IoC-Container nimmt Dir diese Arbeit ab und löst die Abhängigkeiten selber auf und instanziiert Dir diese Klassen mit den Monster-Konstruktoren von alleine.
D.h. eine Factory, die mir das gewünschte Objekt -wie auch immer- zusammenbastelt. Ob nun über DI, oder morgen über Delegates, oder Zusammenfassen von Abhängigkeiten ist dann wieder Schnurz.

D.h. (Hab kein aktuelles Delphi mit Generics, d.h. vielleicht Syntaxfehler)
Delphi-Quellcode:
Function TMyIocContainer.CreateCommand<TCommand : ICommand> : TCommand;
Begin
  result := TCommand.Create(CurrentUser, VCL_UIWrapper, TextFileLogger, FastReportReportingEngine, AnyDACConnection);
End;
Dann ist der Anwender des Containers wieder auf eine Globale Instanz des IocContainers angewiesen. Außer, ich gebe ihm das wieder per DI mit, oder wie?

Kann es sein, dass der Titel falsch ist?
Die globale Instanz einer Klasse ist ja eine globale Variable. Aber ich ändere den Titel.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Globale Variablen = Böse... Und nu?

  Alt 19. Mai 2014, 09:35
Kann es sein, dass der Titel falsch ist?
Die globale Instanz einer Klasse ist ja eine globale Variable. Aber ich ändere den Titel.
Nein muss sie nicht zwangsläufig sein, denn dafür gibt es Möglichkeiten, diese bösen Nebeneffekte (unkontrolliertes und ungeschütztes Überschreiben) von globalen Variablen zu vermeiden:
Delphi-Quellcode:
unit FooUnit;

interface

type
  TFoo = class
  end;

//var
// Foo : TFoo;

function Foo : TFoo;

implementation

var
  _Foo : TFoo;

function Foo : TFoo;
begin
  if not Assigned( _Foo ) then
    _Foo := TFoo.Create;
  Result := _Foo;
end;

finalization

_TFoo.Free;

end.
oder bei neueren Delphi Versionen
Delphi-Quellcode:
unit FooUnit;

interface

type
  TFoo = class
  private
    class var _Foo : TFoo;
    class destructor Destroy;
  public
    class function Default : TFoo;
  end;

implementation

class function TFoo.Default : TFoo;
begin
  if not Assigned( _Foo ) then
    _Foo := TFoo.Create;
  Result := _Foo;
end;

class destructor TFoo.Destroy;
begin
  _Foo.Free;
end;
Trotz allem bleibt aber immer noch die Abhängigkeit bestehen.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (19. Mai 2014 um 09:38 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#5

AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?

  Alt 19. Mai 2014, 10:21
Entschuldigt, aber insbesonders das Problem mit dem "User" kann ich nicht nachvollziehen.
Der Benutzer sitzt vor der Tastatur und ein Anwendungsprogramm hat mit ihm selten etwas zu tun.
Es sei denn es gibt eine Benutzerverwaltung. Und diese sollte den Benutzer "global" bevorraten, und auf Anfrage des "Arbeitsteils" die gewünschten Informationen liefern.

Nicht mehr und nicht weniger.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.645 Beiträge
 
#6

AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?

  Alt 19. Mai 2014, 10:27
Und diese sollte den Benutzer "global" bevorraten, und auf Anfrage des "Arbeitsteils" die gewünschten Informationen liefern.
Damit hast Du wieder eine Abhängigkeit darauf.
Was ist nun, wenn Du den Code automatisch testen willst? Du hast dann keinen User der sich eingeloggt hat, der hier global bereitstehen könnte.

Du willst den Test ggf. mit mehreren gemockten Usern und entsprechenden mehreren Rechte-Kombinationen testen um sicher zu gehen, dass der Code in allen Fällen mit allen notwendigen oder mit fehlenden Rechten wie entsprechend erwartet funktioniert.

Dazu ist es am einfachsten, den jeweils entsprechend präparierten Fake-User für den Test reinzugeben.
Bei einer globalen Abhängigkeit ist es schwierig bis unmöglich das so zu instrumentieren dass für jeden Test der korrekte User geliefert wird.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#7

AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?

  Alt 19. Mai 2014, 10:36
Dazu ist es am einfachsten, den jeweils entsprechend präparierten Fake-User für den Test reinzugeben.
Irgendwas habe ich da nicht verstanden, genau dafür gibt es die Benutzerverwaltung. Eigentlich sollte der Arbeitsteil nur Rechte kennen, der Benutzer dahinter sollte **egal sein.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?

  Alt 19. Mai 2014, 10:55
Abhängigkeit und schwer testbar
Delphi-Quellcode:
unit FooUnit;

interface

type
  TFoo = class
    property Value : string;
  end;

function Foo : TFoo;

implementation

var
  _Foo : TFoo;

function Foo : TFoo;
begin
  if not Assigned( _Foo ) then
    _Foo := TFoo.Create;
  Result := _Foo;
end;

end.
Delphi-Quellcode:
unit BarUnit;

interface

uses
  FooUnit;

type
  TBar = class
    function GetValue : string;
  end;

implementation

function TBar.GetValue : string;
begin
  Result := Foo.Value;
end;

end.
Das sollte man besser so machen:
Delphi-Quellcode:
unit BarUnit;

interface

uses
  FooUnit;

type
  TBar = class
  private
    FFoo : TFoo;
  public
    constructor Create( AFoo : TFoo );
    function GetValue : string;
  end;

implementation

constructor TBar.Create( AFoo : TFoo );
begin
  inherited;
  FFoo := AFoo;
end;

function TBar.GetValue : string;
begin
  Result := FFoo.Value;
end;

end.
Jetzt kann TBar auch mit unterschiedlichen TFoo -Instanzen getestet werden.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:46 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz