AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

globale Variablen

Offene Frage von "AlexanderBrade"
Ein Thema von AlexanderBrade · begonnen am 15. Feb 2009 · letzter Beitrag vom 16. Feb 2009
Antwort Antwort
Seite 2 von 3     12 3      
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.858 Beiträge
 
Delphi 11 Alexandria
 
#11

Re: globale Variablen

  Alt 15. Feb 2009, 14:42
Dann hast du mehrere gloable Variablen durch eine ersetzt, aber hast trotzdem noch eine globale Variable
Markus Kinzler
  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
 
#12

Re: globale Variablen

  Alt 15. Feb 2009, 14:43
logisch, ich brauche einen gemeinsamen Aufhänger ... sonst funzt das ja nicht.

BTW: Jedes erstellte Form ist als globale Variable definiert ...

cu

Oliver
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
Tharon

Registriert seit: 19. Okt 2004
Ort: Frankfurt/Main
12 Beiträge
 
Delphi 2007 Professional
 
#13

Re: globale Variablen

  Alt 15. Feb 2009, 16:47
Hi @all!

Dann gebe ich hier auch mal meinen Senf dazu, denn dieses Thema scheint ja immer noch viele Fragen aufzuwerfen Auch Borland macht es nicht unbedingt toll vor, weshalb man sich natürlich auch nicht wundern darf, dass gerade viele Anfänger immer wieder die gleichen Fehler machen

Also... globale Variablen? Generell nein!

Aber... wie bei jeder Regel gibt es Ausnahmen Und eigentlich ist auch die Frage nach "globalen Variablen" nicht wirklich sinnvoll gestellt, denn es kommt letztendlich darauf an, wie diese deklariert und verwendet werden und wie deren Wert gesetzt/verändert werden kann.

Der Ansatz von Sir Rufo ist ja schon ganz gut... immerhin werden hier schon mal alle globalen Variablen innerhalb einer Klasse gekapselt. Er verwendet zwar einen OOP-Ansatz, dies ist allerdings hier eher eine "Formalität", denn die eigentlichen Probleme, die globale Variablen verursachen, werden nicht gelöst:
  • Mehrfache Instanziierung: Die Klasse TGlobalData kann mehrfach instanziert werden, an beliebigen Stellen im Quellcode.
  • Keine Kontrolle über die Werte: Die Eigenschaften dieser Instanz (entsprechen den "stand alone"-Variablen) können beliebig von jedem Quelltext geändert werden.
Das erste Problem der mehrfachen Instanziierung entspricht genau dem Problem, das AlexanderBrade hatte - er hatte 2 mal die gleiche globale Variable deklariert.

Die Lösungen für diese Probleme sind recht einfach, wenn man den Ansatz von Sir Rufo konsequent weiter verfolgt.

Mehrfache Instanziierung verhindern

Die mehrfache Instanziierung muss verhindert werden - hierfür gibt es ein einfaches Design Pattern: Singleton. Dieses Pattern bewirkt, dass eine Klasse nur ein einziges mal instanziiert werden kann - und das bezeichnet man als "Singleton".
Wie mkinzler schon richtig anmerkte, gäbe es tatsächlich immer noch eine globale Variable für ein Objekt der Klasse TGlobalData, durch die Implementierung als Singleton entfällt nun aber die Notwendigkeit für eine globale Variable!
Jeder Code, der Zugriff auf die gobalen Daten benötigt, fordert über eine Klassenmethode des Singleton (z.B. RetrieveInstance) die (einzige) globale Instanz dieser Klasse an.

Ohne jetzt zu sehr auf alle Details des Singleton Patterns eingehen zu wollen (einfach mal Suchen nach Singleton): der "Trick" besteht darin, dass es keinen öffentlichen Konstruktor gibt, um die beliebige Instanziierung zu verhindern. In Delphi wird einfach der immer vorhandene öffentliche Konstruktor "deaktiviert", indem dieser eine Exception auslöst. Statt dessen implementiert man einen privaten Konstruktor, der von einer Klassenmethode RetrieveInstance aufgerufen wird. Dieser private Konstruktor ruft einfach den geerbten Konstrultor auf.
Die Klassenmethode RetrieveInstance überprüft zunächst, ob bereits eine Instanz existiert und erzeugt ggf. eine Instanz (falls noch nicht vorhanden) über den privaten Konstruktor und liefert diese zurück. Die Klassenmethode RetrieveInstance ist also der Ersatz für den öffentlichen Konstruktor und somit hat die Klasse die volle Kontrolle über ihre Instanziierung.

In meinen Projekten verwende ich eine Singleton-Klasse TGlobalRessources:

Delphi-Quellcode:
unit GlobalRessources;

...

TGlobalRessources = class
  private
    // ...
    constructor _Create; virtual;
  public
    constructor Create; virtual;
    class function RetrieveInstance(): TGlobalRessources;
    // ...
end;


implementation


var
  m_Instance: TGlobalRessources;


constructor TGlobalRessources._Create;
begin
  inherited Create;
end;


constructor TGlobalRessources.Create;
begin
  raise Exception.Create('Trying to instantiate singleton class');
end;


function TGlobalRessources.RetrieveInstance();
begin
  if (m_Instance <> nil) then
  begin
    m_Instance := _Create();
  end;

  Result := m_Instance;
end;


initialization


m_Instance := nil;

// oder, wenn sofortige Instanziierung sinnvoll ist:

m_Instance := TGlobalRessources.RetrieveInstance();


finalization


if (m_Instance <> nil) then
begin
  FreeAndNil(m_Instance);
end;
Ich hoffe, ich habe hier jetzt keine Fehler eingebaut, denn ich habe das jetzt mal eben schnell hier hin getippt, ohne in meinem Code nachzuschauen. Aber es ging mir ja auch nur darum, das Prinzip zu verdeutlichen


Kontrolle über die Variablen-Werte

Schön... jetzt hat man ein globales Objekt, das auch ganz sicher nur ein einziges mal existiert... aber trotzdem kann jetzt immer noch jeder beliebige Code willkürlich die Eigenschaften dieses Objektes (globale Daten) verändern...

Die Lösung dieses Problems ist noch einfacher und lautet: Eigenschaften und Zugriffsmethoden

Wenn man konsequent Zugriffsmethoden für alle Eigenschaften verwendet, erreicht man zumindest schon mal, dass die Wertzuweisungen (natürlich auch das Auslesen) selbst unter der Kontrolle der betreffenden Klasse stehen. Allerdings sollte man bei einer solchen Klasse noch einen Schritt weiter gehen und nach Möglichkeit nur "read only"-Eigenschaften verwenden, also Eigenschaften ohne write-Methode.

Als typisches Beispiel nehme ich mal den am Programm angemeldeten Benutzer. Man könnte nun diverse Properties für den Bennutzer deklarieren (wie UserID, UserName, UserIsAdmin, etc.). Diese Eigenschaften werden dann z.B. von einem Login-Formular gesetzt. Das Problem ist, dass diese Eigenschaften ausser vom Login-Formular auch von jedem beliebigen anderen Code gesetzt werden können und das auch noch unabhängig voneinander!
Beispielsweise könnte man auf die Idee kommen, eine Funktion zu implementieren, die aus dem Programm heraus die Möglichkeit bietet, die Anmeldung zu ändern. Der Entwickler implementiert hierzu vielleicht ein eigenes Formular und verwendet nicht das eigentliche Login-Formular. Außerdem setzt er vielleicht nur die Eigenschaft UserID und "vergisst", dass hiervon noch weitere Eigenschaften abhängen --> "bumm"

Hier sollte man also besser für den angemeldeten Benutzer ein eigenes Objekt vorsehen (bei mir vom Typ TUserProfile). Dieses Objekt UserProfile ist eine öffentliche Eigenschaft der Global Ressorce und kann nur gelesen werden.
Die oben erwähnten Eigenschaften UserID, UserName, UserIsAdmin, etc. sind nun Eigenschaften der Klasse TUserProfile und können ebenfalls nur gelesen werden. Für die Anmeldung stellt die Klasse TUserProfile eine Methode Login zur Verfügung. Ebenso eine Methode, um das Kennwort zu ändern (ChangePwd).

Damit ist folgendes sichergestellt:
  • Es gibt nur ein einziges UserProfile-Objekt, da dieses eine Eigenschaft des Singletons TGlobalRessources ist.
  • Das UserProfile-Objekt selbst kann nicht verändert werden, da es eine "read only"-Eigenschaft des TGlobalRessources-Objektes ist.
  • Die Eigenschaften des angemeldeten Benutzers (UserID, UserName, UserIsAdmin, etc.) sind immer konsistent, da diese nur intern über die Methode Login gesetzt werden.

So.. und jetzt beende ich mal meine Ausführungen... ist ja schon fast ein Tutorial geworden

Liebe Grüße
Thomas
  Mit Zitat antworten Zitat
Cyf

Registriert seit: 30. Mai 2008
407 Beiträge
 
Lazarus
 
#14

Re: globale Variablen

  Alt 15. Feb 2009, 16:58
Warum eine Instanz statt Klassenvariablen verwenden? Und warum überhaupt eine Klasse (außer man möchte natürlich einen Zugriffsschutz über Properties), eine einzige Unit mit allen globalen Variablen tut es imho auch, solange man die Variablen immer mit Unitnamen anspricht und ob es nun Klasse.X oder Unit.X ist, spielt auch keine Rolle.
Man kann einen Barbier definieren als einen, der alle diejenigen rasiert, und nur diejenigen, die sich nicht selbst rasieren.
Rasiert sich der Barbier?
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.858 Beiträge
 
Delphi 11 Alexandria
 
#15

Re: globale Variablen

  Alt 15. Feb 2009, 17:01
Da (Object-)Pascal eine Hybridsprache ist, welche aus einer prozeduralen Sprache entstanden ist, ist es nicht möglich auf gloable Variablen zu verzichten.
Markus Kinzler
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#16

Re: globale Variablen

  Alt 16. Feb 2009, 12:16
Zitat von mkinzler:
Da (Object-)Pascal eine Hybridsprache ist, welche aus einer prozeduralen Sprache entstanden ist, ist es nicht möglich auf gloable Variablen zu verzichten.
Hallo,

ich finde es auch überhaupt nicht sinnvoll: wenn ich z.B. ein Programm zur Dateibearbeitung habe, das genau 1 Datei zur Zeit bearbeitet, dann SIND z.B. die Datei und der Dateiname globale Variablen, und solange ich beim Programmieren des Denkens noch mächtig bin, sehe ich auch garkeinen Grund, diese Tatsache mit fragwürdigen OOP-Konstrukten zu verstecken, nur um das Dogma "niemals global" einzuhalten. Delphi selbst definiert wichtige globale Variablen, z. B. Application.

Nachteilig ist nur, dass Borland es versäumt hat, einen echten globalen Namespace zu schaffen (z.B. durch eine var-Deklaration im dpr-file, oder meinetwegen auch mit "global"), so dass man nicht einfach mit Bordmitteln auf Mehrfachinstanziierung prüfen kann (oder diese von vornherein verhindert wird).

Gruss Reinhard
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

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

Re: globale Variablen

  Alt 16. Feb 2009, 13:54
Hallo zusammen,

wenn ich mich richtig erinnere sind "globale" Variablen PfuiBa weil zu viele Nebeneffekte auftreten können z.B. bei Laufvariablen wie i,j,k.....
Grundsätzlich sollten alle Variablen nur innerhalb einer Routine gültig sein. Und die Übergabe nur über die "offizielle" Schnittstelle erfolgen.
Meiner Meinung nach ist es MANCHMAL sinnvoll in einer "globalen" Variablen Informationen zu hinterlegen, die in der ganzen Anwendung benötigt werden. Das diese Notwendigkeit von dem einen oder anderen cleveren Codebastler mißbraucht wurde, steht auf einem ganz anderen Blatt.
Und wenn schon global, dann sollte man(n) tunlichst vermeiden wild aus einer Subroutine heraus darauf zuzugreifen. (Auch wenn es im Prinzip möglich wäre)

Gruß K-H
  Mit Zitat antworten Zitat
Pfoto

Registriert seit: 26. Aug 2005
Ort: Daun
541 Beiträge
 
Turbo Delphi für Win32
 
#18

Re: globale Variablen

  Alt 16. Feb 2009, 15:50
Zitat von Tharon:
Delphi-Quellcode:
unit GlobalRessources;

...

TGlobalRessources = class
  private
    // ...
    constructor _Create; virtual;
  public
    constructor Create; virtual;
    class function RetrieveInstance(): TGlobalRessources;
    // ...
end;


implementation


var
  m_Instance: TGlobalRessources;


constructor TGlobalRessources._Create;
begin
  inherited Create;
end;

[...]
Zu dem Code von Tharon hätte ich die Frage:

wie kann ich denn nun auf das einmalig instanzierte Objekte zugreifen?

Müsste "m_Instance" deshalb nicht _vor_ dem "implementation" Teil stehen oder gibt es da eine andere vorgehensweise?


Gruß
Jürgen
Jürgen Höfs
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.619 Beiträge
 
Delphi 12 Athens
 
#19

Re: globale Variablen

  Alt 16. Feb 2009, 16:01
Stimmt, die globale Variable muss in den interface-Teil, ansonsten ist sie nicht von außen erreichbar.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Hawkeye219

Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
 
Delphi 2010 Professional
 
#20

Re: globale Variablen

  Alt 16. Feb 2009, 16:03
Hallo,

der Zugriff erfolgt über die Klassenmethode RetrieveInstance, die eine Referenz auf die (einzige) Instanz liefert:

Delphi-Quellcode:
uses
  GlobalRessources;

begin
  TGlobalRessources.RetrieveInstance.<Eigenschaft>
end;
Gruß Hawkeye
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


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 12:56 Uhr.
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