Laden...

Gegenseitiger Klassenzugriff

Erstellt von userid4382 vor 17 Jahren Letzter Beitrag vor 17 Jahren 3.736 Views
U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 17 Jahren
Gegenseitiger Klassenzugriff

Hallo,
mit Bezug auf diesen Thread
Darf ich es wagen?
poste ich hier mein erstes Dokument (in diesem Forum). Ich bitte um Feedback und konstruktive Kritik. =)

Gegenseitiger Klassenzugriff
Man stelle sich folgendes Szenario vor:
Eine WinForms-Anwendung hat, unter anderem, eine Checkbox. In einer anderen Klasse soll der Status dieser Checkbox abgefragt werden, um entsprechende Aktionen durchzuführen (z.B. Änderung eines Codierungsverfahrens).
Man muß also diesen Status an die andere Klasse übergeben.
Nach Durchführung einer entsprechenden Operation soll das Ergebnis wieder in die Forms-Klasse übermitteln werden, damit sie im Form ausgegeben werden kann.
Versucht man es über normale Memberdeklaration wie in diesem Beispiel...


class Class1
   {
      Class2 C2Obj = new Class2();
      /* Code */

   }
   class Class2
   {
      Class1 C1Obj = new Class1();
      /* Code */
   }

... erhält man die Fehlermeldung „infinite Loop“, was auch logisch ist. Das eine Klassenmember enthält eine Referenz auf das Andere. Dieses wiederum auf das Eine.
Hier die Lösung:

 
public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }
      
      private bool CheckBoxFlag = false;
public string MessageText;
      public bool CheckBoxFlagProperty
      {
         get
         {
            return CheckBoxFlag;
         }
      }
      private void checkBox1_CheckedChanged(object sender, EventArgs e)
      {         
         if(CheckBoxFlag)
         {
            CheckBoxFlag = false;
         }
         else
         {
            CheckBoxFlag = true;
         }
         TestClass.CheckBoxMessage(this);
         textBox1.Text=(MessageText);
      }
   }

class TestClass
   { 
      public static void CheckBoxMessage(Form1 CBF)
      {
         if(CBF.CheckBoxFlagProperty)
         {
            CBF.MessageText = "flagged";
         }
         else
         {
            CBF.MessageText = "unflagged";
         }
      }
   }

Hier sieht man mehrere Tricks (naja für Anfänger 😉 ). Im Prinzip dreht sich alles um die Bool-Variable CheckBoxFlag.
Nach deren Deklaration sieht man ein Property. Dieses wird später zu einem Teil eines Klassenmembers der Form1-Klasse.
Über diese Referenzierung wird der Inhalt bzw. der Wert von CheckBoxFlag an die Klasse Testclass übermittelt.
Im Event checkBox1_CheckedChanged wird lediglich das Flag umgesetzt, denn hier wird nur erkannt ob sich die Checkbox geändert hat, aber nicht wie!
Stand das Flag also auf true, wird es auf false gesetzt und umgekehrt.
Jetzt kommt die wirklich interessante Zeile Testclass.CheckBoxMessage(this);.
Da die Methode CheckBoxMessage static ist, braucht man keine Memberdeklaration, sondern kann sie direkt über Testclass. aufrufen.
Das eigentlich interessante hier ist aber das Schlüsselwort this. This ist quasi ein Member der eigenen Klasse und referenziert alle Mitglieder!
Wir brauchen aber doch gar nicht alle Mitglieder – jetzt kommt der zweite, interessante Teil. Schauen wir uns die Deklaration der Methode CheckBoxMessage an:
Zuerst fällt auf daß sie void ist, also gar nichts zurück gibt. Wir brauchen aber etwas zurück. Immer mit der Ruhe.
Als nächstes sehen wir, daß die Methode einen Parameter erwartet, nämlich (Form1 CBF).
Es handelt sich um ein Objekt namens CBF (kurz für CheckBoxFlag), mit dem Typ Form1. Es handelt sich hierbei also um eine Klassenmemberdeklaration der Klasse Form1.
Die übliche Deklaration mit dem Schlüsselwort new wird nicht benötigt, weil es sich hier nur um ein Empfängerobjekt handelt. Die Initialisierung erfolgt ja durch die Parameterübenahme.
Das paßt ja mit dem Methodenaufruf zusammen. Was passiert hier?
Das Objekt CBF referenziert ja wie gesagt die Form1-Klasse.
Mit CBF.CheckBoxFlagProperty wird die Property CheckBoxFlagProperty aufgerufen. Schauen wir uns diese nun an. Sie gibt lediglich den Wert von CheckBoxFlag zurück.
In eine If-Anweisung verpackt, kann nun also entsprechend des Wertes gehandelt werden.
Hinweis: if(CBF.CheckBoxFlagProperty) ist das Gleiche wie if(CBF.CheckBoxFlagProperty == true).
Die Zeile CBF.MessageText = "flagged"; (bzw. unflagged) übergibt ein Textliteral an die Variable Messagetext der Form1-Klasse.
Damit ist die Funktion der Zeile Testclass.CheckBoxMessage(this); abgeschlossen.
Zum Schluß wird der Text noch über textBox1.Text=(MessageText); im Form ausgegeben.

U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 17 Jahren

Man könnte die Methode CheckBoxMessage auch mit Rückgabe machen und das ganze damit vereinfachen. Was mich aber interessierte war die Möglichkeit des gegenseitigen Klassenzugriffs.

F
722 Beiträge seit 2005
vor 17 Jahren

Hallo Cyron,

da du ja kontruktive Kritik hören wolltest:

Was du programmiert hast, nennt man einen Zyklus.
D.h. zwei Klassen (Form1 und TestClass) sind jeweils voneinander abhängig. Die offensichtlich angestrebte Spaltung von Funktionalität in 2 Klassen wurde zwar erreicht, bringt aber näher betrachtet gar nichts. Denn egal welche Klasse du verwendest, immer wirst du auch die andere brauchen um die jeweils andere verwenden zu können.

Das mag sicht jetzt nicht wirklich schlimm anhören, bei steigender Komplexität deines Programms wird dies aber GARANTIERT zu problemen führen.

4.221 Beiträge seit 2005
vor 17 Jahren

Original von Cyron

   
         if(CheckBoxFlag)  
         {  
            CheckBoxFlag = false;  
         }  
         else  
         {  
            CheckBoxFlag = true;  
         }  
  

So was tut doch weh...

Wie wär's mit

 
CheckBoxFlag=!CheckBoxFlag

Im übrigen sehe ich nicht wirklich, was es bringen soll ein Form so weiterzureichen.... Wenn schon würde ich entweder eine Methode erstellen welche ein bool entgegennimmt und einen String returniert... oder eine Methode mit 2 Inputs (Bool-Flag und Combo fürs zurückschreiben)


public string GetCheckText(bool pFlag)
{
return pFlag?"checked":"unchecked";
}

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 17 Jahren

Dankeschön euch beiden.
Und wieder hab ich etwas gelernt. 😁 👍

U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 17 Jahren

Hallo, ich bin's mal wieder. 😁
Wie ich es nicht machen soll, weiß ich ja nun, aber eine gute Lösung fehlt mir noch immer. Es geht mir darum, Form1 sauber zu halten. Nur der Constructor und die Eventhandler sollen verbleiben. Ich hab da nun eine Idee, weiß aber nicht ob das auch wieder Müll ist:

Wie wäre es mit einer Vermittlerklasse?
Wäre eine Singleton-Klasse dafür geeignet?
Sollte ich noch ein Interface dazwischen setzen (warum)?
Es soll so ablaufen:
Die Klasse Form1 übergibt Statusinformation an die
Mediatorklasse.
Von dort holt sich die Testklasse die benötigten Informationen und arbeitet damit.
Danach liefert die Testklasse seine Ergebnisse an die Mediatorklasse,
wo Form1 sie sich abholt.
Damit besteht keine n:m Beziehung zwischen Form1 und Testklasse, sondern nur
1:n Beziehungen zwischen Form1-MediatorClass und TestClass-MediatorClass.

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo Cyron,

ich beziehe mich mal auf folgende Aussage:

Eine WinForms-Anwendung hat, unter anderem, eine Checkbox. In einer anderen Klasse soll der Status dieser Checkbox abgefragt werden, um entsprechende Aktionen durchzuführen (z.B. Änderung eines Codierungsverfahrens).

Hier würde ich folgende Lösung anstreben:

  • Im Form würde ich auf das Event "CheckBox_changed" reagieren, und daraufhin die Methode "ChangeCoding" aus der Businessklasse aufrufen.
  • Die Businessklasse sollte ein Event bieten, das gefeuert wird, falls sich das Kodierverfahren geändert hat
  • Die Forms-Klasse abonniert das Event aus der Businessklasse, da sie das aktuelle Verfahren anzeigen möchte, und eine Änderung von Interesse ist.
  • Dann würde ich tatsächlich vor die Businessklasse ein Interface bauen, damit diese auch austauschbar werden würde

Das hat folgende Vorteile:

  • es ist egal welche, un wieviele Forms auf die Businessklasse zugreifen (es könnten ja noch mehr wie nur die eine sein)
  • Die Businessklasse (darf oder sollte) keine Ahnung haben, welche GUI Klassen auf die eigene Funktionalität zugreifen.

Somit hast Du GUI von Business entkoppelt, und nur durch Events werden Statusänderungen bekanntgegeben...

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

149 Beiträge seit 2005
vor 17 Jahren

Original von Cyron
Wäre eine Singleton-Klasse dafür geeignet?

Es gibt keine Singleton-Klasse; nur ein Singleton Pattern. 😉

lg,
Johann

Schon als Kindern war uns klar: Jeder von uns wird ein Star, oder Millionär - das ist doch auch nicht schwer. Dem Alkohol nicht abgeneigt, war es für uns auch nicht leicht. Durch seine Hände Arbeit, wird man auch nicht gleich ein Scheich.
F
10.010 Beiträge seit 2004
vor 17 Jahren

@Cyron:
Schau Dir lieber mal Pattern wie MVC oder für .NET etwas besser geeignet MVP an.

Die sind zwar im ersten Moment komplex, wenn man es aber einmal verstanden
hat, geht es recht leicht von der hand.

U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 17 Jahren

Vielen Dank für die tollen Tips. =) 👍

P.S.: Man müßte den Entwicklern von SharpDevelop mal stecken daß sie ihr Singleton-Class Template umbenennen sollten.

T
512 Beiträge seit 2006
vor 17 Jahren

Original von John Doe

Original von Cyron
Wäre eine Singleton-Klasse dafür geeignet?

Es gibt keine Singleton-Klasse; nur ein
>
. 😉

lg,
Johann

Ich liebe so schlaue Kommentare.

Eine Klasse, die ein Singleton ist, ist eine Singleton-Klasse.
Ein Pattern ist eben ein Entwurfsmuster.

Genauso könntest du sagen "Es gibt keine Dieselmotoren, es gibt nur Entwurfsmuster für Diesel betriebene Motoren"

e.f.q.

Aus Falschem folgt Beliebiges

5.941 Beiträge seit 2005
vor 17 Jahren

*lol* 🙂)

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011